2020牛客暑期多校第五場E題-Bogo Sort (置換、大數)
阿新 • • 發佈:2020-07-27
題目連結: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\}\)
記 \(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); } }