1. 程式人生 > 實用技巧 >2020牛客暑期多校第五場E題-Bogo Sort (置換、大數)

2020牛客暑期多校第五場E題-Bogo Sort (置換、大數)

題目連結:2020牛客暑期多校第五場E題-Bogo Sort

題意

給出一個置換 \(p\),問 \(1\sim n\)\(n\) 個數有多少種排列,能經過若干次 \(p\) 的置換後變成有序?


思路

題意也等價於有序的 \(1\sim n\) 經過 \(p\) 的若干次置換,能形成多少種不同的排列。

記置換 \(P\)\(z\) 個環,長度分別為 \(C_1,C_2,...,C_z\)\(1\sim n\) 分別經過 \(x_1\)\(x_2\) 次置換後,記 \(S_1=\{x_1\%C1,x_1\%C_2,...,x_1\%C_z\},S_2=\{x_2\%C1,x_2\%C_2,...,x_2\%C_z\}\)

,當且僅當 \(S_1\ne S_2\) ,則形成的排列不同。

\(L=lcm(C_1,C_2,...,C_z)\) ,當 \(|x_1-x_2|\ne y\cdot L, y\in N^*\) ,有 \(S_1\ne S_2\) 。顯然最多有 \(L\) 個不同的 \(x\) ,滿足 \(|x_i-x_j|\ne y\cdot L, i\in[1,L],j\in [1,L],i\ne j\) ,即最多形成 \(L\) 種不同的排列,所以答案為 \(L\)


程式碼實現

import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Scanner;
 
public class Main{
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        int p[] = new int[n+10];
        boolean vis[] = new boolean[n+10];
        for (int i = 1; i <= n; i++) p[i] = sc.nextInt();
        ArrayList<Integer> C = new ArrayList<Integer>();
        for (int i = 1; i <= n; i++) {
            int ci = 0, tmp = i;
            while (!vis[tmp]) {
                vis[tmp] = true;
                ci++;
                tmp = p[tmp];
            }
            if (ci > 0) C.add(ci);
        }
        BigInteger ans = BigInteger.ONE;
        for (int ci : C) {
            BigInteger g = ans.gcd(BigInteger.valueOf(ci));
            ans = ans.multiply(BigInteger.valueOf(ci)).divide(g);
        }
        System.out.println(ans);
    }
}