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

题目链接

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

题目大意

给你一个置换 B , 要求找到置换 P 使得 $PA^{k}=B$ , 其中 A 为 P 的置换规则

解题思路 

置换是满足逆元关系的

$P=PA^{k}A^{-k}=BA^{-k}$

一个置换的某个位置的某个数在改变了一定次数后一定会变回它自己,即每个位置都属于某个环中 

我们设某个环的大小为 len , 那么这个环中的数置换的次数为 k % len

我们设 t = k % len , 那么根据 t * t^-1 = 1 , 我们只要让这个环中的每个数再改变 t^-1次

就可以回到初始的位置 , 而 t^-1 即是 k 在 % len 下的逆元

AC_Code

#include<bits/stdc++.h>
#define int long long
#define ll long long 
using namespace std;
ll exgcd1(ll a,ll b,ll &x,ll &y){if(!b){x=1,y=0;return a;}ll t=exgcd1(b,a%b,y,x);y-=a/b*x;return t;}
ll get_inv(ll a,ll mod){ll x,y;ll d=exgcd1(a,mod,x,y);return d==1?(x%mod+mod)%mod:-1;}
const int N = 3e5 + 10;
int a[N] , vis[N] , ans[N];
vector<int>vec;
signed main()
{
    ios::sync_with_stdio(false) , cin.tie(0) , cout.tie(0);
    int n , k;
    cin >> n >> k ;
    for(int i = 1 ; i <= n ; i ++) cin >> a[i];
    for(int i = 1 ; i <= n ; i ++)
    {
        if(vis[i]) continue ;
        vec.clear();
        vec.push_back(i) , vis[i] = 1;
        int now = a[i];
        while(now != i)
        {
            vec.push_back(now) , vis[now] = 1;
            now = a[now];
        }
        int sz = vec.size() , ny = get_inv(k , sz);
        for(int j = 0 ; j < sz ; j ++) ans[vec[j]] = vec[(j + ny) % sz];
    }
    for(int i = 1 ; i <= n ; i ++) cout << ans[i] << " ";
    cout << '\n';
    return 0;
}
posted @ 2020-07-20 16:36  GsjzTle  阅读(284)  评论(1编辑  收藏  举报