This way
现在有n个人,然后有m次操作,每次操作都做长度为k的约瑟夫,然后再按照淘汰的顺序再做约瑟夫,直到x次。问你最终的序列是怎么样的。
这种题目我就不是很懂。首先用权值线段树 O ( n l o g n ) O(nlogn) O(nlogn)求出置换。只要每次查看当前位置后面的值够不够,如果不够的话,减掉后面值的个数,然后回到1,然后求从p开始有now个还存在的数的位置。
置换求出来了之后,好像可以用倍增做,但是也有可以快速求经过了x步的做法,然后置换是有两种表示形式的:
就拿第一个样例来举例子
第一种置换是 3 1 5 2 4,a[i]表示上一个在a[i]位置的数会变到i位置
第二种置换:2 4 1 5 3,a[i]表示当前在i位置上的数在下一步会变到a[i]位置
然后对于第二种置换,假设要变换x步,那么第i个位置上的数会变到a[(i+x%len)%len]上。len表示循环的长度,因为位置只在循环内变动。
然后再将答案按照这个置换走一下即可。
#include
using namespace std;
const int N=1e5+5;
int num[N*4];
void build(int l,int r,int root){
if(l==r){
num[root]=1;
return ;
}
int mid=l+r>>1;
build(l,mid,root<<1);
build(mid+1,r,root<<1|1);
num[root]=num[root<<1]+num[root<<1|1];
}
void update(int l,int r,int root,int p){
if(l==r){
num[root]--;
return ;
}
int mid=l+r>>1;
if(mid>=p)
update(l,mid,root<<1,p);
else
update(mid+1,r,root<<1|1,p);
num[root]=num[root<<1]+num[root<<1|1];
}
int q_sum(int l,int r,int root,int ql,int qr){
if(l>=ql&&r<=qr)
return num[root];
int mid=l+r>>1;
int ans=0;
if(mid>=ql)
ans=q_sum(l,mid,root<<1,ql,qr);
if(mid<qr)
ans+=q_sum(mid+1,r,root<<1|1,ql,qr);
return ans;
}
int q_pos(int l,int r,int root,int v){
if(l==r)return l;
int mid=l+r>>1;
if(num[root<<1]>=v)
return q_pos(l,mid,root<<1,v);
else
return q_pos(mid+1,r,root<<1|1,v-num[root<<1]);
}
int a[N],ans[N];
int n,m;
int k,x;
void finds(){//找约瑟夫环
int cnt=0;
for(int i=1;i<=n;i++){
int now=k;
if(now+cnt>num[1])
now+=cnt-num[1];
else
now+=cnt;
now%=num[1];
if(!now)now=num[1];
int p=q_pos(1,n,1,now);
a[i]=p;
update(1,n,1,p);
if(p-1)
cnt=q_sum(1,n,1,1,p-1);
else
cnt=0;
}
}
int tmp[N],vis[N],ttmp[N];
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)ans[i]=i;
while(m--){
build(1,n,1);
memset(vis,0,sizeof(vis));
scanf("%d%d",&k,&x);
finds();
for(int i=1;i<=n;i++)//求置换
tmp[a[i]]=i;
for(int i=1;i<=n;i++)
a[i]=tmp[i];
for(int i=1;i<=n;i++){
if(vis[i]==1)continue;
int top=0,now=i;
vis[now]=1;
tmp[top++]=now;
int ne=a[now];
while(!vis[ne]){
tmp[top++]=ne;
now=ne,vis[now]=1,ne=a[now];
}
int res=x%top;
for(int j=0;j<top;j++)//快速置换
ttmp[tmp[j]]=tmp[(j+res)%top];
}
for(int i=1;i<=n;i++)a[i]=ttmp[i];
for(int i=1;i<=n;i++)
tmp[a[i]]=ans[i];
for(int i=1;i<=n;i++)
ans[i]=tmp[i];
}
for(int i=1;i<=n;i++)
printf("%d%c",ans[i]," \n"[i==n]);
return 0;
}