Josephus Transform(置换群&树状数组)

思路:置换群&树状数组。

考虑:用树状数组维护第 k k k位置的编号。

然后我们需要求出 k k k对于的置换 p p p。

p [ i ] p[i] p[i]表示的含义是 编号为 i i i的对应人的位置是 p [ i ] p[i] p[i]。

然后进行快速幂,得到编号为 i i i对应的人的位置是 a n s [ i ] ans[i] ans[i]。

因为要按位置输出,所以修改一下, p [ a n s [ i ] ] = i p[ans[i]]=i p[ans[i]]=i。

注意不能反过来快速幂,即设 p [ i ] p[i] p[i]为位置 i i i对应的编号,最后直接输出 a n s [ i ] ans[i] ans[i],这样是错的,因为树状数组维护的是编号 i i i,而不是位置。

时间复杂度: O ( n m l o g n ) O(nmlogn) O(nmlogn)

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e5+5,M=2e4+5,inf=0x3f3f3f3f,mod=1e9+7;
#define mst(a) memset(a,0,sizeof a)
#define lowbit(x) x&(-x)
int tr[N],n,m,ans[N],p[N];
void upd(int x,int k){
while(x<=n){
tr[x]+=k;x+=lowbit(x);
}
}
int kth(int k){
int ans=0,cnt=0;
for(int i=20;~i;i--){
ans+=1<<i;
if(ans>=n||cnt+tr[ans]>=k) ans-=1<<i;
else cnt+=tr[ans];
}
return ans+1;
}
void mul(int *a,int *b){
static int tmp[N];
for(int i=1;i<=n;i++) tmp[i]=b[a[i]];
memcpy(a+1,tmp+1,sizeof(int)*n);
}
void ksm(int n){
while(n){
if(n&1) mul(ans,p);
mul(p,p);
n>>=1;
}
}
void modify(){
int k,x;
scanf("%d%d",&k,&x);
for(int i=1;i<=n;i++) upd(i,1);
int pos=0;
for(int i=1;i<=n;i++){
pos=(pos+k-1)%(n-i+1);
int now=kth(pos+1);
upd(now,-1);
p[now]=i;
}
ksm(x);
}
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++) ans[i]=i;
while(m--) modify();
for(int i=1;i<=n;i++) p[ans[i]]=i;
for(int i=1;i<=n;i++) printf("%d ",p[i]);
return 0;
}