Submission #1308630

#TimeUsernameProblemLanguageResultExecution timeMemory
1308630orzorzorzSnake Escaping (JOI18_snake_escaping)C++20
100 / 100
585 ms21844 KiB
#include <iostream> #include <vector> #include <string> #include <algorithm> using namespace std; // 全域陣列,大小為 2^20 (每個約 4MB) // A: 儲存原始毒性值 // dp_sub: 儲存子集和 (Subset Sum) // dp_super: 儲存超集和 (Superset Sum) int A[1 << 20]; int dp_sub[1 << 20]; int dp_super[1 << 20]; int main() { // 優化 I/O 操作速度 ios_base::sync_with_stdio(false); cin.tie(NULL); int L, Q; if (!(cin >> L >> Q)) return 0; string S; cin >> S; int N = 1 << L; // 初始化陣列 for (int i = 0; i < N; ++i) { A[i] = S[i] - '0'; dp_sub[i] = A[i]; dp_super[i] = A[i]; } // 1. 建構 SOS DP (子集和) // dp_sub[mask] = 所有 i 是 mask 的子集的 A[i] 之和 for (int i = 0; i < L; ++i) { for (int mask = 0; mask < N; ++mask) { if (mask & (1 << i)) { dp_sub[mask] += dp_sub[mask ^ (1 << i)]; } } } // 2. 建構 SOS DP (超集和) // dp_super[mask] = 所有 i 是 mask 的超集的 A[i] 之和 for (int i = 0; i < L; ++i) { // 從大到小枚舉,或者直接檢查第 i 位是否為 0 for (int mask = N - 1; mask >= 0; --mask) { if (!(mask & (1 << i))) { dp_super[mask] += dp_super[mask | (1 << i)]; } } } char T[25]; for (int q = 0; q < Q; ++q) { cin >> T; int mask0 = 0; // 必須是 '0' 的位置集合 (Set A) int mask1 = 0; // 必須是 '1' 的位置集合 (Set B) int maskQ = 0; // 是 '?' 的位置集合 (Set C) int c0 = 0, cQ = 0; // 解析詢問字串 T // 注意:題目通常定義 T[0] 對應最高位 (2^(L-1)) 或最低位,需根據題目調整 // 這裡假設 T[0] 對應最高位 2^(L-1) for (int i = 0; i < L; ++i) { int bit = L - 1 - i; if (T[i] == '0') { mask0 |= (1 << bit); c0++; } else if (T[i] == '1') { mask1 |= (1 << bit); } else { maskQ |= (1 << bit); cQ++; } } int ans = 0; // 策略 1: '?' 很少 -> 暴力枚舉 '?' if (cQ <= 6) { // 枚舉 maskQ 的所有子遮罩 (submask) for (int s = maskQ; ; s = (s - 1) & maskQ) { // 索引值 = 固定的 1 (mask1) + 當前 '?' 變成的 1 (s) ans += A[mask1 | s]; if (s == 0) break; } } // 策略 2: '0' 很少 -> 對 '0' 使用排容原理 (搭配超集和) else if (c0 <= 6) { // 基礎:mask1 必須是 1。maskQ 隨意。mask0 "應該" 是 0。 // dp_super[mask1] 給出 mask1 位元為 1 的所有和 (此時 mask0 可能是 0 或 1)。 // 我們需要扣除那些 mask0 中某些位元變成 1 的情況。 for (int s = mask0; ; s = (s - 1) & mask0) { int val = dp_super[mask1 | s]; // 如果 s 中有奇數個 1,則減去;偶數個則加上 (排容原理) if (__builtin_popcount(s) & 1) ans -= val; else ans += val; if (s == 0) break; } } // 策略 3: '1' 很少 -> 對 '1' 使用排容原理 (搭配子集和) else { // 隱含條件:c1 <= 6 // 基礎:mask0 必須是 0。maskQ 隨意。mask1 "應該" 是 1。 // dp_sub[mask1 | maskQ] 給出 mask0 位元為 0 的所有和 (此時 mask1 可能是 0 或 1)。 // 我們需要扣除那些 mask1 中某些位元變成 0 的情況。 for (int s = mask1; ; s = (s - 1) & mask1) { // 我們將 s 中的位元關掉 (強制變為 0) // 查詢的 mask 變為 (mask1 去掉 s) | maskQ int val = dp_sub[(mask1 ^ s) | maskQ]; if (__builtin_popcount(s) & 1) ans -= val; else ans += val; if (s == 0) break; } } cout << ans << "\n"; } return 0; }
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...