結果
| 問題 |
No.868 ハイパー部分和問題
|
| コンテスト | |
| ユーザー |
qwewe
|
| 提出日時 | 2025-05-14 12:55:54 |
| 言語 | C++17 (gcc 13.3.0 + boost 1.87.0) |
| 結果 |
WA
|
| 実行時間 | - |
| コード長 | 7,475 bytes |
| コンパイル時間 | 623 ms |
| コンパイル使用メモリ | 77,124 KB |
| 実行使用メモリ | 7,844 KB |
| 最終ジャッジ日時 | 2025-05-14 12:57:49 |
| 合計ジャッジ時間 | 17,435 ms |
|
ジャッジサーバーID (参考情報) |
judge5 / judge2 |
(要ログイン)
| ファイルパターン | 結果 |
|---|---|
| sample | AC * 2 |
| other | AC * 37 WA * 1 |
ソースコード
#include <iostream>
#include <vector>
#include <numeric>
// Define the modulo constant
// Using a common prime modulus for competitive programming.
const int MOD = 998244353;
// Function to compute (base^exp) % mod using binary exponentiation
// This is efficient for large exponents.
long long power(long long base, long long exp) {
long long res = 1;
base %= MOD; // Ensure base is within modulo range
while (exp > 0) {
// If exponent is odd, multiply result with base
if (exp % 2 == 1) res = (res * base) % MOD;
// Square the base and halve the exponent
base = (base * base) % MOD;
exp /= 2;
}
return res;
}
// Function to compute modular inverse using Fermat's Little Theorem
// This works because MOD is a prime number.
// The modular inverse of n is n^(MOD-2) % MOD.
long long modInverse(long long n) {
// Check if n is divisible by MOD. If so, inverse doesn't exist.
// This handles cases like n=0 or n being a multiple of MOD.
if (n % MOD == 0) {
// Error case: inverse does not exist.
// In this problem, we only need the inverse of 2. Since MOD is odd, 2 is not divisible by MOD.
// So this check is mostly for robustness.
return -1; // Indicates an error or non-existence.
}
// Calculate n^(MOD-2) % MOD
return power(n, MOD - 2);
}
// Precompute modular inverse of 2, as it's used when handling elements with value 0.
// Initialized to -1 to indicate it hasn't been computed yet.
long long inv2 = -1;
// Global vector to store polynomial coefficients. poly[s] stores the number of ways to form sum s.
// We only care about whether the count is non-zero, but tracking counts modulo MOD allows reversibility.
std::vector<int> poly;
// Global variable for the target sum K.
int K;
/**
* @brief Adds the effect of an element with value A_val to the subset sums polynomial.
*
* This function updates the polynomial P(x) representing achievable sums to P(x) * (1 + x^A_val).
* This corresponds to considering the subsets including A_val and those not including it.
* The update rule is p_new[s] = p[s] + p[s - A_val].
*
* @param A_val The value of the element being added.
*/
void add_val(int A_val) {
// Handle the special case where the element value is 0.
if (A_val == 0) {
// Adding 0 doesn't change the sum, but doubles the number of ways to achieve existing sums.
// Equivalent to multiplying the polynomial by (1 + x^0) = (1 + 1) = 2.
for (int i = 0; i <= K; ++i) {
// Multiply each coefficient by 2 modulo MOD.
poly[i] = (int)((poly[i] * 2LL) % MOD);
}
return;
}
// If A_val > K, including it in a subset will always result in a sum greater than K.
// Thus, it doesn't affect the coefficients up to x^K.
// P(x) * (1 + x^A_val) mod x^(K+1) = P(x) mod x^(K+1). No operation needed.
if (A_val > K) return;
// Update the polynomial coefficients using the dynamic programming relation.
// We iterate s backwards from K down to A_val to ensure that we use the coefficient poly[s - A_val]
// from the *previous* state (before it was updated in the current step).
for (int s = K; s >= A_val; --s) {
// p_new[s] = (p_old[s] + p_old[s - A_val]) % MOD
poly[s] = (int)((poly[s] + (long long)poly[s - A_val]) % MOD);
}
}
/**
* @brief Removes the effect of an element with value A_val from the subset sums polynomial.
*
* This function updates the polynomial P(x) to P(x) / (1 + x^A_val).
* This reverses the operation performed by add_val.
* The update rule is derived from P(x) = P_new(x) * (1 + x^A_val), which gives P_new(x) = P(x) / (1 + x^A_val).
* Let P_new(x) = Q(x). Then P(x) = Q(x) + x^A_val * Q(x).
* Coefficient-wise, p_s = q_s + q_{s - A_val}. This gives q_s = p_s - q_{s - A_val}.
*
* @param A_val The value of the element being removed.
*/
void remove_val(int A_val) {
// Handle the special case where the element value is 0.
if (A_val == 0) {
// Removing 0 is equivalent to dividing the polynomial by (1 + x^0) = 2.
// Multiply each coefficient by the modular inverse of 2.
// Compute inv2 once if it hasn't been computed yet.
if (inv2 == -1) inv2 = modInverse(2);
for (int i = 0; i <= K; ++i) {
// Multiply by inv2 modulo MOD. Use long long for intermediate product.
poly[i] = (int)(((long long)poly[i] * inv2) % MOD);
}
return;
}
// If A_val > K, removing it has no effect on coefficients up to x^K,
// because it wasn't affecting them in the first place.
// P(x) / (1 + x^A_val) mod x^(K+1) = P(x) / 1 mod x^(K+1) = P(x). No operation needed.
if (A_val > K) return;
// Compute the new coefficients q_s = p_s - q_{s - A_val}.
// Iterate s forwards from 0 to K. When computing q_s, we need q_{s - A_val}.
// If we update poly[s] in place, the value poly[s - A_val] will hold the already computed q_{s - A_val}.
for (int s = 0; s <= K; ++s) {
// Check if s >= A_val to avoid accessing negative indices.
if (s >= A_val) {
// Calculate q_s = (p_s - q_{s - A_val}) % MOD.
// Add MOD before taking modulo to handle potential negative results from subtraction.
// Use long long for intermediate subtraction to avoid potential underflow/wrap-around issues before adding MOD.
poly[s] = (int)(((long long)poly[s] - poly[s - A_val] + MOD) % MOD);
}
// If s < A_val, then q_{s - A_val} is considered 0 (no terms with negative index).
// So q_s = p_s. Since poly[s] already holds p_s, no change is needed.
}
}
int main() {
// Optimize standard I/O operations for speed.
std::ios_base::sync_with_stdio(false);
std::cin.tie(NULL);
int N; // Number of elements in the sequence
std::cin >> N >> K; // Read N and target sum K
std::vector<int> A(N); // Vector to store the current sequence elements
poly.resize(K + 1, 0); // Resize polynomial coefficient vector to hold coefficients up to K
poly[0] = 1; // Initialize P(x) = 1, representing the empty set which sums to 0 in one way.
// Process the initial array elements
for (int i = 0; i < N; ++i) {
std::cin >> A[i]; // Read the i-th element
add_val(A[i]); // Incorporate its effect into the polynomial
}
int Q; // Number of updates/queries
std::cin >> Q;
// Precompute modular inverse of 2 if needed (for elements with value 0).
inv2 = modInverse(2);
// Process each query
for (int i = 0; i < Q; ++i) {
int x; // 1-based index of the element to change
int v; // The new value for the element
std::cin >> x >> v;
--x; // Convert to 0-based index for vector access
remove_val(A[x]); // Remove the effect of the old value A[x] from the polynomial
A[x] = v; // Update the value in the array
add_val(A[x]); // Add the effect of the new value v to the polynomial
// After update, check if the coefficient of x^K (poly[K]) is non-zero.
// A non-zero coefficient means sum K is achievable.
if (poly[K] != 0) {
std::cout << 1 << "\n"; // Output 1 if K is achievable
} else {
std::cout << 0 << "\n"; // Output 0 otherwise
}
}
return 0; // Indicate successful execution
}
qwewe