Josephus Transform

题目链接

题目大意

一个长度为n的排列,初始为1……n。
有m次操作:
每次操作是进行y次 k-约瑟夫变换 。
这个变换就是:先把1……n写成一个环,然后从1开始找到第k个,把这个数加到b里,把这个数在环里删去,从这个位置下一个 继续找第k个,直到数字被删完。
1<=n<=1e5
1<=m<=1e5
1<=n * m<=1e6

题解

求进行一次k-约瑟夫变换得到的排列b,可以用线段树求出来,复杂度是n*logn.
进行y次变换也就是用b排列把1……n置换y次。
怎么置换呢?
可以发现置换满足结合律。
也就是说 对a进行两次b置换就相当于 先把b进行一次b置换,然后把a进行一次b置换就好了。
然后就可以用快速幂了。
我怎么就想不到,巨巨们太强了,妙啊妙啊
代码:

#include<algorithm>
#include<cstring>
#include <iostream>
#include <cstdio>
#include <queue>
#include <map>
#include <set>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;
typedef pair<double,double> pdd;
typedef unsigned long long ull;
typedef set<int>::iterator sit;
#define st first
#define sd second
#define mkp make_pair
#define pb push_back
void wenjian(){
   freopen("concatenation.in","r",stdin);freopen("concatenation.out","w",stdout);}
void tempwj(){
   freopen("hash.in","r",stdin);freopen("hash.out","w",stdout);}
ll gcd(ll a,ll b){
   return b == 0 ? a : gcd(b,a % b);}
ll qpow(ll a,ll b,ll mod){
   a %= mod;ll ans = 1;while(b){
   if(b & 1)ans = ans * a % mod;a = a * a % mod;b >>= 1;}return ans;}
struct cmp{
   bool operator()(const pii & a, const pii & b){
   return a.second < b.second;}};
int lb(int x){
   return  x & -x;}
//friend bool operator < (Node a,Node b) 重载
const int inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3f;
const ll mod = 1e9 + 7;
const int maxn = 5e5+10;
struct Node
{
   
	int l,r,num;
}node[maxn];

void build(int l,int r,int no)
{
   
	node[no].l = l;
	node[no].r = r;
	node[no].num = r - l + 1;
	if(l == r)
	{
   
		return;
	}
	int mid = l +r >> 1;
	build(l,mid,no<<1);
	build(mid + 1,r,no<<1|1);
}

void update(int pos,int num,int no)
{
   
	node[no].num += num;
	if(node[no].l == node[no].r)
		return;
	int mid = node[no].l + node[no].r >> 1;
	if(pos <= mid)
		update(pos,num,no<<1);
	else
		update(pos,num,no<<1|1);
}
int query(int k,int no)
{
   
	if(node[no].l == node[no].r)
		return node[no].l;
	int s = node[no<<1].num;
	if(k <= s)
		return query(k,no<<1);
	else
		return query(k - s,no<<1|1);

}
int n;
int temp[maxn];
void solve(int a[],int b[])
{
   
	for (int i = 1; i <= n; i ++ )
	{
   
		temp[i] = a[b[i]];
	}
	for (int i = 1; i <= n; i ++ )
		a[i] = temp[i];
}
int b[maxn];
int a[maxn];

void qui(int num)
{
   
	while(num)
	{
   
		if(num & 1)
		{
   
			solve(a,b);
		}
		num >>= 1;
		solve(b,b);
	}
}

int main()
{
   
	int m;
	scanf("%d%d",&n,&m);
	for (int i = 1; i <= n; i ++ )
			a[i] = i;
	while(m -- )
	{
   
		build(1,n,1);
		int x,y;
		scanf("%d%d",&x,&y);
		int cnt = n;
		int pos = 1;
		
		for (int i = 1; i <= n; i ++ )
		{
   
			int k = (pos - 1 + x - 1) % cnt + 1;

			cnt -- ;
			b[i] = query(k,1);
			//printf("%d %d\n",k,b[i]);
			update(b[i],-1,1);
			pos = k;
		}
		// for (int i = 1; i <= n; i ++ )
		// printf("%d ", b[i]);
		// cout<<endl;
		qui(y);
		
	}
	for (int i = 1; i <= n; i ++ )
	{
   
		printf("%d ",a[i]);
	}
	printf("\n");
}