原题请看这里
给定长度为 n n n的排列 P P P ( ( (初始 P P P = = = { \{ { 1 , 2 , . . . , n 1,2,...,n 1,2,...,n } \} } ) ) )和 m m m次操作。每次操作可以用 ( k , x ) (k,x) (k,x)表示,代表执行 x x x次 k − k- k−约瑟夫变换。请输出最后的排列。
k − k- k−约瑟夫变换表示:将排列 P P P排成一个环,从第一位开始逐个数数,将数到 k k k的元素删除,并添加到一个新的排列 P ′ P' P′ 中。然后继续从下一个数开始数数。重复上述操作,直到所有元素都被添加到 P ′ P' P′ 中, P ′ P' P′ 就是结果。例如 { \{ { 1 , 2 , 3 , 4 , 5 1,2,3,4,5 1,2,3,4,5 } \} } 在执行 3 − 3- 3−约瑟夫变换后可以得到 { \{ { 3 , 1 , 5 , 2 , 4 3,1,5,2,4 3,1,5,2,4 } \} }
第一行包含两个整数 n , m n,m n,m ( ( ( 1 1 1 ≤ \le ≤ n n n, m m m ≤ \le ≤ 1 0 5 10 ^ 5 105, 1 1 1 ≤ \le ≤ n n n × \times × m m m ≤ \le ≤ 1 0 6 10 ^ 6 106 ) ) )接下来 m m m行每行包含两个整数 k k k, x x x ( ( ( 1 1 1 ≤ \le ≤ k k k ≤ \le ≤ n n n, 1 1 1 ≤ \le ≤ x x x ≤ \le ≤ 1 0 9 10 ^ 9 109 ) ) ),表示一项操作 ( ( ( k k k, x x x ) ) )
一行,打印 n n n个整数。
5 1
3 1
3 1 5 2 4
5 2
3 3
2 3
1 2 3 4 5
置换群!
又是置换群!!
怎么还是置换群!!!
为什么牛客多校有那么多置换群!!!!
前几场牛客置换群相关题解:
第二场 J u s t S h u f f l e Just Shuffle JustShuffle
第五场 B o g o S o r t Bogo Sort BogoSort
手动模拟了一下,你就会发现变几次之后就回去了…不信你可以把题目给的样例手算试试看,直接就想到置换群…
第一时间想到暴力求,一看到 m m m的取值范围就放弃了(赛场上K题一直卡着)
作为牛客多校的特色置换群,这题与前几场的置换群题目稍有不同,需要使用树状数组(或线段树)来维护。
如果上一个被取出来的数字是 t t t,当前还剩 c n t cnt cnt个数,那么下一个被选出来的数字应该是剩下数字的第 ( t + k − 2 ) (t+k-2) (t+k−2) m o d mod mod c n t + 1 cnt+1 cnt+1 个,这时记录这个序列就需要树状数组(或线段树)来处理了,时间复杂度 O ( n l o g n ) O(nlogn) O(nlogn)。然后可以用类似于快速幂的方法来做x次k-约瑟夫变换,时间复杂度 O ( n l o g x ) O(nlogx) O(nlogx)
处理方法:二分+树状数组+置换群
时间复杂度: O ( n m ( l o g n + l o g x ) ) O(nm(logn+logx)) O(nm(logn+logx))
(呜呜呜写的好烂,欢迎 d a l a o dalao dalao前来指正和提点)
线段树写法
#include
using namespace std;
const int MAXN=1e5+5;
int n,q,k,x,sum[MAXN],a[MAXN],b[MAXN],c[MAXN],t,l,r;
int find(int x){
int ans=0;
for(int i=x;i;i-=(i&(-i)))
ans+=sum[i];
return ans;
}
void use(int mid){
for(int i=mid;i<=n;i+=(i&(-i)))
sum[i]++;
}
int main(){
scanf("%d%d",&n,&q);
for(int i=1;i<=n;i++)
a[i]=i;
while(q--){
scanf("%d%d",&k,&x);
for(int i=1;i<=n;i++) sum[i]=0;//memset会超时......只能手动清零
t=1;
for(int i=1;i<=n;i++){
t=(t+k-2)%(n-i+1)+1,l=1,r=n;
while(l<r){
int mid=l+r>>1;
if(mid-find(mid)>=t) r=mid;
else l=mid+1;
}//二分
b[i]=l;
use(l);
}
while(x){
if(x&1){
for(int i=1;i<=n;i++)
c[i]=a[b[i]];
for(int i=1;i<=n;i++)
a[i]=c[i];
}
for(int i=1;i<=n;i++)
c[i]=b[b[i]];
for(int i=1;i<=n;i++)
b[i]=c[i];
x>>=1;
}
}
for(int i=1;i<=n;i++)
printf("%d ",a[i]);
puts("");
}