2020牛客暑期多校训练营(第六场)J-Josephus Transform 群置换,约瑟夫环

J-Josephus Transform

题意

对排列\(P=\left\{ 1,2,\dots,n \right\}\)\(m\)次操作,每次操作给一对数\(k,x\),表示对\(P\)\(x\)次步长为\(k\)的约瑟夫变换,求出最终的\(P\)排列。

分析

先考虑如何求一个\(k\)-约瑟夫变换,注意每次取出的数字是剩下的几个数字中的第几个是可以算出来的,设上一次被取出的数字是当时的第\(pos\)个(初始设为 \(1\)),当前还剩下 \(cnt\) 个数字,那么下一 个被选出来的数应该是当前剩下的所有数字中的第 \((pos-1+k-1) \% cnt + 1\) 个,用线段树来求编号为\(k\)的数,对数字从\(1\sim 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?'\n':' ');
    return 0;
}

posted @ 2020-08-13 01:50  xyq0220  阅读(140)  评论(0编辑  收藏  举报