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

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;
}

原文地址:https://www.cnblogs.com/xyq0220/p/13494076.html