J Just Shuffle(序列跳转)
题:https://ac.nowcoder.com/acm/contest/5667/J
题意:要求构造出序列P,让初始排列A={1,2,3,4....n}依照P序列跳转k次后得到给定排列。
分析:简单分析可发现,若存在合法情况的话,跳转的过程肯定在若干个简单环上;
我们可以简单模拟,设每个环大小为mi,在环中的每个数会达到跳转后的k%m步,我们可以用数组来模拟这一步,如果每一个环都能跑满大小为mi 的数组且不重复即存在方案(只需gcd(mi,k%m)==1)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<bits/stdc++.h> using namespace std; #define pb push_back #define MP make_pair typedef long long ll; const int mod=998244353; const int M=2e5+6; const int inf=0x3f3f3f3f; const ll INF=1e18; int to[M],book[M],lin[M],ans[M]; vector<int>tmp; int main(){ int n,k; scanf("%d%d",&n,&k); for(int i=1;i<=n;i++) scanf("%d",&to[i]); for(int i=1;i<=n;i++){ if(!book[i]){ tmp.clear(); int nowi=i; tmp.pb(nowi); book[nowi]=1; while(!book[to[nowi]]){ nowi=to[nowi]; tmp.pb(nowi); book[nowi]=1; } int m=tmp.size();///环大小 if(m==1){ ans[tmp[0]]=tmp[0]; continue; } int x=k%m;///需要跳多少步才能到达 if(__gcd(m,x)!=1) return puts("-1"),0; nowi=0; for(auto v:tmp){ lin[nowi]=v; nowi+=x; nowi%=m; } for(int i=0;i<m;i++) ans[lin[i]]=lin[(i+1)%m]; } } for(int i=1;i<=n;i++) printf("%d ",ans[i]); }