結果
問題 |
No.1327 グラフの数え上げ
|
ユーザー |
![]() |
提出日時 | 2025-05-14 13:13:24 |
言語 | C++17 (gcc 13.3.0 + boost 1.87.0) |
結果 |
TLE
|
実行時間 | - |
コード長 | 6,189 bytes |
コンパイル時間 | 664 ms |
コンパイル使用メモリ | 75,768 KB |
実行使用メモリ | 21,644 KB |
最終ジャッジ日時 | 2025-05-14 13:14:31 |
合計ジャッジ時間 | 4,168 ms |
ジャッジサーバーID (参考情報) |
judge2 / judge4 |
(要ログイン)
ファイルパターン | 結果 |
---|---|
sample | AC * 4 |
other | AC * 12 TLE * 1 |
ソースコード
#include <iostream> #include <string> #include <vector> #include <algorithm> #include <stdexcept> // For std::stoll exception // Define the modulus P const long long P = 1000000007; // Function for modular exponentiation (base^exp % MOD) // Uses unsigned long long for intermediate products to prevent overflow long long power(long long base, long long exp) { long long res = 1; base %= P; // Ensure base is within [0, P-1] while (exp > 0) { if (exp % 2 == 1) { // Multiply result by base, using unsigned long long for intermediate product res = (unsigned long long)res * base % P; } // Square the base, using unsigned long long for intermediate product base = (unsigned long long)base * base % P; exp /= 2; // Halve the exponent } return res; } // Function for modular multiplicative inverse using Fermat's Little Theorem // Calculates n^(P-2) mod P long long modInverse(long long n) { // Ensure n is within [0, P-1] before calculating inverse n %= P; if (n < 0) n += P; // Handle potential negative input, although unlikely in this context // Inverse exists only for n != 0 mod P. // In our context, n is product of terms N to P-1. If N < P, none are 0 mod P. // So product is non-zero mod P. Inverse exists. if (n == 0) { // This case should not happen based on the logic and constraints. // If it occurs, it indicates an error. // std::cerr << "Error: Modular inverse requested for 0." << std::endl; return 0; // Or handle error appropriately } return power(n, P - 2); } int main() { // Use faster I/O operations std::ios_base::sync_with_stdio(false); std::cin.tie(NULL); std::string N_str; // Read N as a string std::cin >> N_str; // String representations of P and P+1 for comparison std::string P_str = "1000000007"; std::string P_p1_str = "1000000008"; // Case 1: N >= P+1 // Compare N as string with "1000000008". // If N_str is longer, or same length and lexicographically >= P_p1_str, then N >= P+1. if (N_str.length() > P_p1_str.length() || (N_str.length() == P_p1_str.length() && N_str >= P_p1_str)) { // (N-1)! contains P as a factor, so (N-1)! = 0 mod P. // S(N) = (N-1)! * (-1)^(N-1) = 0 * (...) = 0 mod P. std::cout << 0 << std::endl; return 0; } // Case 2: N = P // Check if N_str is exactly the string representation of P. if (N_str == P_str) { // S(P) = (P-1)! * (-1)^(P-1) mod P // By Wilson's Theorem, (P-1)! = -1 mod P. // Since P = 10^9+7 is an odd prime > 2, P-1 is even. (-1)^(P-1) = 1. // S(P) = (-1) * 1 = -1 mod P. // -1 mod P is P-1. std::cout << P - 1 << std::endl; return 0; } // Case 3: 2 <= N < P // N must be converted from string to long long. // Since N < P, it fits within a standard 64-bit signed long long. long long N; try { N = std::stoll(N_str); } catch (const std::out_of_range& oor) { // This should not happen given the length/string comparisons above. // If it does, it indicates an unexpected issue. std::cerr << "Error: N string parsing failed unexpectedly for value < P." << std::endl; return 1; // Exit with error code } // Constraint check: Problem statement guarantees N >= 2. // If N happens to be less than 2, print error and exit. if (N < 2) { std::cerr << "Error: N < 2 encountered, constraint N >= 2 violated." << std::endl; return 1; // Exit with error code } // Now we need to compute S(N) = (N-1)! * (-1)^(N-1) mod P for 2 <= N < P. // This requires computing (N-1)! mod P. long long factN_1; // Variable to store (N-1)! mod P // Optimization: Choose faster method to compute (N-1)! mod P. // Method 1: Direct computation: 1 * 2 * ... * (N-1). Takes O(N) time (N-2 multiplications). // Method 2: Inverse property: (N-1)! = (-1) * (product_{k=N}^{P-1} k)^{-1} mod P. Based on Wilson's Thm. Takes O(P-N) time (P-N multiplications + 1 modular inverse O(log P)). // Compare costs: N-2 vs P-N. Direct is faster if N-2 < P-N => 2N < P+2 => N <= (P+1)/2. // Threshold for P = 10^9+7 is (10^9+7+1)/2 = 10^9+8 / 2 = 500000004. // Let's use threshold = (P + 2) / 2 for integer arithmetic precision. P is odd, P+2 is odd. floor((P+2)/2) = (P+1)/2. long long threshold = (P + 1) / 2; // Threshold = 500000004 if (N <= threshold) { // Compute (N-1)! directly. Best for smaller N. factN_1 = 1; for (long long i = 1; i < N; ++i) { // Use unsigned long long for intermediate product to prevent overflow factN_1 = (unsigned long long)factN_1 * i % P; } } else { // Compute (N-1)! using inverse property. Best for larger N (closer to P). // (N-1)! = (-1) * (product_{k=N}^{P-1} k)^{-1} mod P long long prod_N_to_P_1 = 1; // Calculate product N * (N+1) * ... * (P-1) mod P. Loop runs from N up to P-1. for (long long k = N; k < P; ++k) { prod_N_to_P_1 = (unsigned long long)prod_N_to_P_1 * k % P; } // Calculate modular inverse of the product long long inv_prod = modInverse(prod_N_to_P_1); // Calculate (N-1)! = (-1 * inv_prod) mod P // Ensure result is positive: (P - inv_prod) % P is equivalent to -inv_prod mod P factN_1 = (P - inv_prod) % P; } // Final result S(N) = (N-1)! * (-1)^(N-1) mod P long long result; if ((N - 1) % 2 == 0) { // Check if N-1 is even (i.e., N is odd) // If N-1 is even, (-1)^(N-1) = 1. S(N) = (N-1)! mod P. result = factN_1; } else { // N-1 is odd (i.e., N is even) // If N-1 is odd, (-1)^(N-1) = -1. S(N) = -(N-1)! mod P. // Ensure result is positive: (P - factN_1) % P is equivalent to -factN_1 mod P. result = (P - factN_1) % P; } // Print the final result followed by a newline. std::cout << result << std::endl; return 0; // Successful execution }