結果
| 問題 |
No.1978 Permutation Repetition
|
| コンテスト | |
| ユーザー |
qwewe
|
| 提出日時 | 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;
}
qwewe