J-Josephus Transform
题意
对排列(P=left{ 1,2,dots,n ight})做(m)次操作,每次操作给一对数(k,x),表示对(P)做(x)次步长为(k)的约瑟夫变换,求出最终的(P)排列。
分析
先考虑如何求一个(k)-约瑟夫变换,注意每次取出的数字是剩下的几个数字中的第几个是可以算出来的,设上一次被取出的数字是当时的第(pos)个(初始设为 (1)),当前还剩下 (cnt) 个数字,那么下一 个被选出来的数应该是当前剩下的所有数字中的第 ((pos-1+k-1) \% cnt + 1) 个,用线段树来求编号为(k)的数,对数字从(1sim n)建线段树,初始值都为(1),被取出后置为(0),编号为(k)的数即为前缀和等于(k)的位置,可以在线段树上二分求出。
求出(k)-约瑟夫变换后,就可以对(P)做置换了,群置换是满足结合律的,所以可以用快速幂来算,设(k)-约瑟夫变换排列为(a),把置换看做乘法,那么对(P)做(x)次置换即为(P cdot a^x),快速幂求出(a^x),然后再用(a^x)对(P)做一次置换就可以了。
Code
#include<algorithm>
#include<iostream>
#include<cstring>
#include<iomanip>
#include<sstream>
#include<cstdio>
#include<string>
#include<vector>
#include<bitset>
#include<queue>
#include<cmath>
#include<stack>
#include<set>
#include<map>
#define rep(i,x,n) for(int i=x;i<=n;i++)
#define per(i,n,x) for(int i=n;i>=x;i--)
#define sz(a) int(a.size())
#define rson mid+1,r,p<<1|1
#define pii pair<int,int>
#define lson l,mid,p<<1
#define ll long long
#define pb push_back
#define mp make_pair
#define se second
#define fi first
using namespace std;
const double eps=1e-8;
const int mod=1e9+7;
const int N=1e6+10;
const int inf=1e9;
int n,m;
int tr[N<<2],a[N],A[N],B[N],tmp[N];
void bd(int l,int r,int p){
if(l==r) return tr[p]=1,void();
int mid=l+r>>1;
bd(lson);bd(rson);
tr[p]=tr[p<<1]+tr[p<<1|1];
}
void up(int x,int l,int r,int p){
if(l==r) return tr[p]=0,void();
int mid=l+r>>1;
if(x<=mid) up(x,lson);
else up(x,rson);
tr[p]=tr[p<<1]+tr[p<<1|1];
}
int find(int x,int l,int r,int p){
if(l==r) return l;
int mid=l+r>>1;
if(tr[p<<1]<x) return find(x-tr[p<<1],rson);
else return find(x,lson);
}
void change(int k){
bd(1,n,1);
int pos=1;
rep(i,1,n){
pos=(pos+k-2)%(n-i+1)+1;
int x=find(pos,1,n,1);
a[i]=x;
up(x,1,n,1);
}
}
void mul(int a[],int b[]){
rep(i,1,n) tmp[i]=a[b[i]];
rep(i,1,n) a[i]=tmp[i];
}
void ksm(int x){
rep(i,1,n) B[i]=i;
while(x){
if(x&1) mul(B,a);
x>>=1;
mul(a,a);
}
}
int main(){
//ios::sync_with_stdio(false);
//freopen("in","r",stdin);
scanf("%d%d",&n,&m);
rep(i,1,n) A[i]=i;
while(m--){
int k,x;
scanf("%d%d",&k,&x);
change(k);
ksm(x);
mul(A,B);
}
rep(i,1,n) printf("%d%c",A[i],i==n?'
':' ');
return 0;
}