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; }
凡所不能将我击倒的,都将使我更加强大