結果
問題 |
No.243 出席番号(2)
|
ユーザー |
![]() |
提出日時 | 2025-05-14 13:05:06 |
言語 | C++17 (gcc 13.3.0 + boost 1.87.0) |
結果 |
AC
|
実行時間 | 18 ms / 2,000 ms |
コード長 | 5,081 bytes |
コンパイル時間 | 648 ms |
コンパイル使用メモリ | 74,612 KB |
実行使用メモリ | 6,272 KB |
最終ジャッジ日時 | 2025-05-14 13:06:53 |
合計ジャッジ時間 | 1,782 ms |
ジャッジサーバーID (参考情報) |
judge1 / judge2 |
(要ログイン)
ファイルパターン | 結果 |
---|---|
sample | AC * 3 |
other | AC * 30 |
ソースコード
#include <iostream> #include <vector> #include <numeric> // Using long long for safety in calculations involving potentially large numbers // Standard library includes useful functions and types. using namespace std; // Define the modulus as a constant integer. // The problem requires calculations modulo 10^9 + 7. const int MOD = 1000000007; int main() { // Optimize standard input/output operations for speed. ios_base::sync_with_stdio(false); cin.tie(NULL); int N; // Number of students cin >> N; // Read the number of students from input. // Vector `count` stores the frequency of each disliked number. // The size is N because attendance numbers are from 0 to N-1. // Disliked numbers A_i >= N are irrelevant because they can never be assigned. vector<int> count(N, 0); for (int i = 0; i < N; ++i) { int A_i; // Disliked number for student S_i cin >> A_i; // Read the disliked number for student i. // We only care about constraints where the disliked number A_i is // within the range of possible attendance numbers [0, N-1]. if (A_i >= 0 && A_i < N) { // Increment the count for the disliked number A_i. // This indicates one more student dislikes this number. count[A_i]++; } } // Precompute factorials modulo MOD up to N. // `fact[k]` will store k! mod MOD. Factorials are needed for the inclusion-exclusion formula. vector<long long> fact(N + 1); fact[0] = 1; // Base case: 0! = 1 for (int i = 1; i <= N; ++i) { // Calculate k! = (k-1)! * k. // Use `(long long)i` to cast `i` to long long before multiplication // to prevent potential overflow if `fact[i-1]` and `i` are large, even if their product fits in long long. fact[i] = (fact[i - 1] * (long long)i) % MOD; } // Vector `C` will store the coefficients of the polynomial P(z) = product_{j=0}^{N-1} (1 + count[j] * z). // The coefficient C[k] (i.e., coefficient of z^k) represents the number of ways to choose k students // such that their disliked numbers are all distinct. This is the term denoted as C_k in the inclusion-exclusion formula. // The size is N+1 because the polynomial can have degree up to N. vector<long long> C(N + 1, 0); C[0] = 1; // Initialize the polynomial as P(z) = 1. The coefficient of z^0 is 1. int current_deg = 0; // Keep track of the current degree of the polynomial P(z). // Build the polynomial P(z) iteratively. // For each number j from 0 to N-1: for (int j = 0; j < N; ++j) { // If number j is disliked by at least one student (count[j] > 0): if (count[j] > 0) { long long c = count[j]; // c is the number of students who dislike number j. // Multiply the current polynomial (represented by coefficients in C) by the factor (1 + c*z). // Update the coefficients C[i] in place. // To correctly update in place, we must iterate from the highest possible new degree downwards. // This ensures that when calculating the new C[i], we use the value of C[i-1] from the *previous* polynomial state. // The formula for the new coefficient C'[i] is: C'[i] = old C[i] * 1 + old C[i-1] * c. for (int i = current_deg + 1; i >= 1; --i) { // Calculate the term to add: (old C[i-1] * c) % MOD long long term_to_add = (C[i - 1] * c) % MOD; // Update C[i]: new C[i] = (old C[i] + term_to_add) % MOD C[i] = (C[i] + term_to_add) % MOD; } // Note: C[0] remains unchanged because the update formula for i=0 would be C'[0] = old C[0] + old C[-1]*c. Since C[-1] is conceptually 0, C'[0]=old C[0]. // After multiplying by (1 + c*z), the degree of the polynomial increases by 1. current_deg++; } } // Calculate the final answer using the principle of inclusion-exclusion. // The formula is: Answer = sum_{k=0}^{N} (-1)^k * C_k * (N-k)! long long ans = 0; // Initialize the answer to 0. // Iterate through k from 0 up to the computed degree of the polynomial P(z). // Note: C_k will be 0 for k > current_deg, so we don't need to sum further. for (int k = 0; k <= current_deg; ++k) { // Calculate the k-th term of the sum: C_k * (N-k)! mod MOD long long term = (C[k] * fact[N - k]) % MOD; // Add or subtract the term based on the sign (-1)^k. // Check if k is even or odd. if (k % 2 == 0) { // If k is even, the sign is +1. ans = (ans + term) % MOD; // Add the term to the answer. } else { // If k is odd, the sign is -1. // Subtract the term. Add MOD before taking modulo to handle potential negative results correctly. ans = (ans - term + MOD) % MOD; } } // Output the final computed answer. cout << ans << endl; return 0; // Indicate successful execution. }