2020牛客暑期多校训练营(第二场)J. Just Shuffle

链接

https://ac.nowcoder.com/acm/contest/5667/J

题意

求序列 ${1,2,3,…,n}$ 按照 $P$ 置换 $k$($10^8\le k\le 10^9$,$k$ 为质数) 次后为 $A$,已知 $k$ 和 $A$,求按照 $P$ 置换一次后的序列

思路

设原序列为 $E$,$E*P^k=P^k=A$

找出所有循环置换,对于某个循环置换,设 $sz$ 为环的大小,$U$ 为 $P$ 的子序列,$V$ 为 $A$ 的子序列,那么 $U^{k%sz}=V$,$V^{k^{-1}%sz}=U$

因为 $\gcd(k,sz)=1$,又因为模数较小,所以对于 $kx%sz=1$ 可以枚举 $x$ 求出逆元

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+5;
int n,p[N],cnt,vis[N],res[N];
int m;
vector<int> v[N];
void find_cycle(int x) {
if(vis[x]) return;
vis[x]=cnt;
v[cnt].push_back(x);
find_cycle(p[x]);
}
int main() {
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++) scanf("%d",&p[i]);
for(int i=1;i<=n;i++) {
if(vis[i]) continue;
++cnt;
find_cycle(i);
int sz=v[cnt].size(),inv;
for(int j=0;j<sz;j++) if(1ll*m*j%sz==1) {inv=j;break;}
for(int j=0;j<sz;j++) res[v[cnt][j]]=v[cnt][(j+inv)%sz];
}
for(int i=1;i<=n;i++) printf("%d ",res[i]);
puts("");
return 0;
}