2020牛客多校二J Just Shuffle (数论)

题意:问哪个置换执行k次后可以把123……n变成给出的序列,如不存在这样的置换输出-1,其中k为素数。

分析:根据置换的性质,置换是由环组成的,由于k是素数,所以无论环的周期m是多少,m和k%m都是互素的,所以一定存在满足要求的置换,所以由数论知识一定可以找到一个b使得b*(k%m)==1(mod m),这样就可以将给出的序列乘上b次,就得出了符合要求的置换,具体的那个置换逻辑比较绕,看了半天也还是很迷,之后遇到置换最好还是写一下。

代码:

#include <bits/stdc++.h>
#define x first
#define y second
#define mid (l+r>>1)
#define lo (o<<1)
#define ro (o<<1|1)
using namespace std;
typedef long long ll;
typedef pair<int,int>pii;
typedef vector<int>vi;
struct tri{int x,y,z;};
const int inf=0x3f3f3f3f;
const ll linf=0x3f3f3f3f3f3f3f3f;
const int N=1e5+10;
const ll mod=1e9+7;
const double PI=acos(0)*2;

int n,m,k,arr[N],v[N];
bool vis[N];
void f()
{
    if(m==1)return;

    ll a=k%m,b=1;
    for(;a*b%m!=1;b++);

    for(int i=0;i<m;i++)
        arr[v[i]]=v[(i+b)%m];
}
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);cout.tie(0);
//    freopen("in.txt","r",stdin);
    cin>>n>>k;
    for(int i=1;i<=n;i++)cin>>arr[i];
    for(int i=1;i<=n;i++)if(!vis[i])
    {
        m=0;
        for(int j=i;;)
        {
            vis[j]=1;
            v[m++]=j;//由于求的是环,这里j或者arr[j]一样
            j=arr[j];
            if(j==i)break;
        }//这一操作实际上是求出置换这条链的逆过程
        f();
    }
    for(int i=1;i<=n;i++)
        cout<<arr[i]<<' ';
    return 0;
}
/*
 *样例置换:2 3 1
 *等价于:
 *1->3
 *2->1
 *3->2
 *求出的数组v:1 2 3(变化为1->3->2->1->...)
 */

猜你喜欢

转载自blog.csdn.net/qq_43700916/article/details/108643759