結果
問題 |
No.1978 Permutation Repetition
|
ユーザー |
![]() |
提出日時 | 2025-05-14 13:18:14 |
言語 | C++17 (gcc 13.3.0 + boost 1.87.0) |
結果 |
AC
|
実行時間 | 6 ms / 2,000 ms |
コード長 | 5,778 bytes |
コンパイル時間 | 1,106 ms |
コンパイル使用メモリ | 91,184 KB |
実行使用メモリ | 7,844 KB |
最終ジャッジ日時 | 2025-05-14 13:19:05 |
合計ジャッジ時間 | 2,627 ms |
ジャッジサーバーID (参考情報) |
judge5 / judge2 |
(要ログイン)
ファイルパターン | 結果 |
---|---|
sample | AC * 2 |
other | AC * 44 |
ソースコード
#include <iostream> #include <vector> #include <numeric> #include <map> #include <vector> #include <utility> // For std::swap // Define the modulus const long long MOD = 1000000007; // Function to compute (base^exp) % MOD using binary exponentiation long long power(long long base, long long exp) { long long res = 1; base %= MOD; while (exp > 0) { if (exp % 2 == 1) res = (res * base) % MOD; base = (base * base) % MOD; exp /= 2; } return res; } // Function to compute modular inverse using Fermat's Little Theorem // Assumes MOD is prime and n is not a multiple of MOD long long modInverse(long long n) { // Check if n is 0 modulo MOD, though this shouldn't happen for factorials unless N >= MOD if (n % MOD == 0) return 0; // Should handle this case if possible, but not expected here return power(n, MOD - 2); } // Function to compute GCD (Greatest Common Divisor) using Euclidean algorithm // Handles non-negative inputs. Assumes a, b >= 0. long long gcd(long long a, long long b) { while (b) { a %= b; std::swap(a, b); } return a; } // Define MAXN based on problem constraints N <= 1000 const int MAXN = 1005; long long fact[MAXN]; long long invFact[MAXN]; // Precompute factorials and their modular inverses up to N void precompute_factorials(int n) { fact[0] = 1; invFact[0] = 1; for (int i = 1; i <= n; ++i) { fact[i] = (fact[i - 1] * i) % MOD; invFact[i] = modInverse(fact[i]); } } // Function to compute combinations C(n, k) mod MOD using precomputed values long long combinations(int n, int k) { // Check for invalid inputs if (k < 0 || k > n) { return 0; } // Compute C(n, k) = n! / (k! * (n-k)!) using modular inverses // C(n, k) = (n! * inv(k!)) % MOD * inv((n-k)!) % MOD long long res = (fact[n] * invFact[k]) % MOD; res = (res * invFact[n - k]) % MOD; return res; } int main() { // Use faster I/O std::ios_base::sync_with_stdio(false); std::cin.tie(NULL); int N; long long M; // M can be large, up to 10^9 std::cin >> N >> M; std::vector<int> A(N + 1); // Permutation A, 1-indexed for (int i = 1; i <= N; ++i) { std::cin >> A[i]; } // Precompute factorials and their modular inverses up to N precompute_factorials(N); // Map to store counts of cycles by length: {length: count} std::map<int, int> cycle_len_counts; std::vector<bool> visited(N + 1, false); // Track visited elements // Find cycle decomposition of permutation A for (int i = 1; i <= N; ++i) { if (!visited[i]) { int current = i; int count = 0; // Length of the current cycle // Traverse the cycle while (!visited[current]) { visited[current] = true; current = A[current]; count++; } // Increment the count for cycles of this length cycle_len_counts[count]++; } } long long total_ans = 1; // Initialize total answer std::vector<long long> dp(N + 1); // DP table for computing contributions for each cycle length L // Iterate through each distinct cycle length L found in A and its count N_L for (auto const& [L_int, N_L] : cycle_len_counts) { long long L = (long long)L_int; // Use long long for L in calculations // Find the set S_L of valid group sizes k. // k is a valid group size if k divides M and gcd(M/k, L) = 1. std::vector<int> S_L; for (int k = 1; k <= N_L; ++k) { // k must be at least 1 and at most N_L if (M % k == 0) { // Check if k divides M long long M_div_k = M / k; // Check the gcd condition. Use long long version of L. if (gcd(M_div_k, L) == 1) { S_L.push_back(k); } } } // Dynamic programming calculation for N_L cycles of length L dp[0] = 1; // Base case: 0 cycles contribute 1 way (empty product) for (int i = 1; i <= N_L; ++i) { // Compute dp[i] for i cycles dp[i] = 0; // Initialize dp[i] // Iterate through all valid group sizes k in S_L for (int k : S_L) { if (k > i) continue; // Group size k cannot exceed current number of cycles i // Calculate N(k, L) = (k-1)! * L^(k-1) mod MOD // This is the number of ways to form P cycles from k cycles of A long long N_k_L; if (k == 1) { N_k_L = 1; // (1-1)! * L^(1-1) = 0! * L^0 = 1 * 1 = 1 } else { // Calculate L^(k-1) mod MOD long long L_pow_k_minus_1 = power(L, k - 1); // N(k, L) = (k-1)! * L^(k-1) N_k_L = (fact[k - 1] * L_pow_k_minus_1) % MOD; } // Calculate combinations C(i-1, k-1) mod MOD // This represents choosing k-1 cycles to group with a fixed cycle long long combinations_val = combinations(i - 1, k - 1); // Calculate the term for this k: C(i-1, k-1) * N(k, L) * dp[i-k] mod MOD long long term = (combinations_val * N_k_L) % MOD; term = (term * dp[i - k]) % MOD; // Add this term to dp[i] dp[i] = (dp[i] + term) % MOD; } } // Multiply the total answer by the result for this cycle length L total_ans = (total_ans * dp[N_L]) % MOD; } // Output the final computed answer std::cout << total_ans << std::endl; return 0; }