置换(群)&(J Just Shuffle)

牛客上多校第二场的J题,下来补的时候发现要置换群,于是就来学了,然后就想着记个笔记,这里记几篇资源。
https://wenku.baidu.com/view/7b373e6b561252d380eb6ee5.html
https://blog.csdn.net/weixin_44412226/article/details/107395789

置换(群)

置换

先说置换是啥
对于一个n个元素集合 S = { a 1 , a 2 . . . a n } S = \{a_1,a_2...a_n\} S={a1,a2...an},排列 P = { p 1 , p 2 . . . p n } P = \{p_1,p_2...p_n\} P={p1,p2...pn},将排列P每个元素当做S的下标替换掉原本S每个元素的位置,就得到一个置换 f = { a p 1 , a p 2 . . . a p n } f = \{a_{p_1},a_{p_2}...a_{p_n}\} f={ap1,ap2...apn}
可以写作
f = ( a 1 , a 2 , . . . a n a p 1 , a p 2 . . . a p n ) f=\left( \begin{array}{c} {a_1,a_2,...a_n}\\ {a_{p_1},a_{p_2}...a_{p_n}} \end{array} \right) f=(a1,a2,...anap1,ap2...apn)
由于排列有 n ! n! n!种,所以置换也会有 n ! n! n!

置换的环

有一个排列为 A = ( 2 , 3 , 1 , 5 , 4 ) A= (2,3,1,5,4) A=(2,3,1,5,4)
还有一个排列为 P = ( 3 , 1 , 2 , 5 , 4 ) P=(3,1,2,5,4) P=(3,1,2,5,4),将A通过P进行置换可以得到:

  1. 置换第一次: ( 1 , 2 , 3 , 4 , 5 ) (1,2,3,4,5) (1,2,3,4,5)
  2. 置换第二次: ( 3 , 1 , 2 , 5 , 4 ) (3,1,2,5,4) (3,1,2,5,4)
  3. 置换第三次: ( 2 , 3 , 1 , 4 , 5 ) (2,3,1,4,5) (2,3,1,4,5)
  4. 置换第四次: ( 1 , 2 , 3 , 5 , 4 ) (1,2,3,5,4) (1,2,3,5,4)

从上面的结果就足以看出规律来了。

  1. 置换是可以分成块的:也就是(2,3,1)和(4,5)这两个块,你可以发现无论怎么置换都不会发生这两个集合的元素之间互换。
  2. 存在循环:也就是对于每个块,在置换一定次数之后就会变回原样,比如(2,3,1)这个块在置换三次后就会变回原来排列中的位置
  3. 每个环的(下面不叫块了叫环)循环的大小就是块的元素的数目

对于上面的置换,有两个环(1,2,3)和(4,5),大小为3和2,那么上述的置换可以拆成这两个环,。

可以证明所有的置换都可以拆成若干个环 w 1 , w 2 . . . w n w_1,w_2...w_n w1,w2...wn, 而每个环的大小为 r 1 , r 2 . . . r n r_1,r_2...r_n r1,r2...rn,也就是说对于环 w i w_i wi在对原排列置换 r i r_i ri次后保持不变,那么也就可以得到原排列置换 l c m ( r 1 , r 2 . . . r n ) lcm(r_1,r_2...r_n) lcm(r1,r2...rn)次后保持不变。

一些关系

对于排列A,使用置换P置换K次后得到B,记为 A k = B A^k = B Ak=B,如果A的所有环的最小公倍数大小为C,那么 A C = A A^C = A AC=A

若:
A A A A 1 A^1 A1使用的置换是P
A A A A 2 A^2 A2则是把置换P向后转动一次
A A A A 3 A^3 A3则是转动P两次

比如对于排列A = (2,3,1),置换P = (3,1,2)
A 1 A^1 A1(相当于置换一次从A到 A 1 A^1 A1)为(1,2,3)
A 2 A^2 A2 = (3,1,2)
A 3 A^3 A3 = (2,3,1)
把从A到 A 2 A^2 A2的置换记做P’,那么可以得到P’ = (2,3,1)与P相比就相当于把P的所有元素向右转了一下。
根据上面关系可以得到在P置换下的 A 2 g A^{2g} A2g = 在P转动一次下置换下的 A g A^{g} Ag
注意:
上述关系的成立前提是k与A的环的大小互质

J Just Shuffle

这道题让求一个置换P,给出指定的排列 B = ( 1 , 2 , 3 , . . , n ) B = (1,2,3,..,n) B=(1,2,3,..,n),和排列 A A A,和一个整数K,使在P置换下 B k = A B^k = A Bk=A

首先可以很简单的求出一个置换 P 0 P_0 P0满足 B 1 = A B^1 = A B1=A,但是题要求是 B K = A B^K = A BK=A所以还需要在变化,由于置换是有环的,假设 P 0 P_0 P0有若干个环, R 1 , R 2 . . . R n R_1,R_2...R_n R1,R2...Rn大小为 r 1 , r 2 , . . . r n r_1,r_2,...r_n r1,r2,...rn那么对于第i个环有
R i k = R i k % r i R_i^k = R_i^{k \% r_i} Rik=Rik%ri,由于置换转一下就增一倍,所以置换转 i n v inv inv下时相对于原来就转了 k ∗ i n v k*inv kinv下,而最终我们的目的是是让他等于1,所以就有 k ∗ i n v = 1 ( m o d r i ) k*inv = 1(mod r_i) kinv=1(modri)成立即inv为k的逆元,也就是说当原本的环的置换转inv下时就是答案了。

#include<bits/stdc++.h>
#define INF 0x3f3f3f3f
#define ll long long
#define pb push_back
#define eps 1e-8
#define endl '\n'
using namespace std;
const ll maxn = 1e6 + 5;
int n,k,a[maxn],ans[maxn];
bool vis[maxn];
vector<int> v;
void setSubstitution(){
    int r = v.size(),inv;//r为环的大小,inv为k在r下的逆元
    for(int i = 0; i < r; i++)
        if((ll) k * i % r == 1)inv = i;//求逆元
    for(int i = 0; i < r; i++)
        ans[v[i]] = v[(i + inv) % r];//转inv次
}
int main(){
    scanf("%d %d",&n,&k);
    for(int i = 1; i <= n; i++)
        scanf("%d",a + i);
    for(int i = 1; i <= n; i++){
        if(!vis[i]){
            v.clear();
            int x = a[i];
            while(!vis[x]){//找环操作
                v.push_back(x);
                vis[x] = 1;
                x = a[x];
            }
            setSubstitution();
        }
    }
    for(int i = 1; i <= n; i++)
        printf("%d ",ans[i]);
    return 0;
}
©️2020 CSDN 皮肤主题: 深蓝海洋 设计师:CSDN官方博客 返回首页