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