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)

#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]);
}
View Code
原文地址:https://www.cnblogs.com/starve/p/13298859.html