Submission #1144283

#TimeUsernameProblemLanguageResultExecution timeMemory
1144283monkey133Snake Escaping (JOI18_snake_escaping)C++20
22 / 100
2095 ms59624 KiB
#include <bits/stdc++.h> using namespace std; // For clarity we use int for indices (since n is small) and ll for values that might be larger. typedef long long ll; // Fast bit–reversal for an n–bit number (assumes n <= 32) inline int reverse_bits(int x, int n) { int r = 0; for (int i = 0; i < n; i++) { r = (r << 1) | (x & 1); x >>= 1; } return r; } int main(){ ios::sync_with_stdio(false); cin.tie(nullptr); int n, q; cin >> n >> q; string toxic2; cin >> toxic2; // Precompute powers of 3. vector<ll> three(25); three[0] = 1; for (int i = 1; i < 25; i++) three[i] = three[i - 1] * 3; // Reorder the toxic string using bit–reversal. int totStates = 1 << n; string toxic = toxic2; for (int i = 0; i < totStates; i++) { int newmask = reverse_bits(i, n); toxic[i] = toxic2[newmask]; } // m is the number of “prefix digits” (m <= 5) int m = min(5, n - 1); // dp is defined over states of length (n-m) digits (each digit in {0,1,2}). int dpSize = three[n - m]; vector<int> dp(dpSize, 0); // Precompute hh[]: for each binary mask of length (n-m), convert it into a base–3 number // where a 0–bit gives a digit 1 and a 1–bit gives a digit 2. int binarySize = 1 << (n - m); vector<int> hh(binarySize, 0); for (int i = 0; i < binarySize; i++){ int sum = 0; for (int j = 0; j < n - m; j++){ if (i & (1 << j)) sum += 2 * three[j]; else sum += three[j]; } hh[i] = sum; } // Read query strings and compute a “mask” for each. // In our construction, each query’s value is stored as // mask = sum_{j=0}^{n-1} (digit * three[j]) // where digit is 1 for character '0' and 2 for character '1'. vector<ll> mask(q, 0); // Also precompute the lower m digits (low part) and the remaining high part. vector<int> low(q, 0); vector<int> high(q, 0); for (int i = 0; i < q; i++){ string ss; cin >> ss; ll val = 0; for (int j = 0; j < n; j++){ if (ss[j] == '0') val += three[j]; else if (ss[j] == '1') val += 2 * three[j]; } mask[i] = val; low[i] = val % three[m]; // lower m digits high[i] = val / three[m]; // remaining digits } // Precompute a lookup table for the prefix condition. // For each possible pref (a binary number with m bits) and each possible value x // (the lower m digits, where x is in [0, three[m]) corresponding to m ternary digits), // we require that: // - if the i-th bit of pref is 0, then the i-th digit (base 3) is 0 or 1. // - if the i-th bit of pref is 1, then the i-th digit is 0 or 2. int prefSize = 1 << m; int lowRange = three[m]; vector<vector<bool>> valid(prefSize, vector<bool>(lowRange, true)); for (int pref = 0; pref < prefSize; pref++){ for (int x = 0; x < lowRange; x++){ bool ok = true; int temp = x; for (int i = 0; i < m; i++){ int d = temp % 3; temp /= 3; if (d == 1 && (pref & (1 << i))) { ok = false; break; } if (d == 2 && !(pref & (1 << i))) { ok = false; break; } } valid[pref][x] = ok; } } vector<int> ans(q, 0); // Outer loop over all possible prefixes. // (There are only 2^m possibilities, at most 32.) for (int pref = 0; pref < prefSize; pref++){ // Reset dp. fill(dp.begin(), dp.end(), 0); // Initialize dp: // For each binary mask of length (n-m), we compute an index into our dp state // via hh[] and set dp[state] = toxic[ index2 ] where: // index2 = pref + (j * (1 << m)) // This corresponds to the way you rearranged toxic. int binarySize2 = 1 << (n - m); for (int j = 0; j < binarySize2; j++){ int state = hh[j]; int index2 = pref + j * (1 << m); dp[state] = toxic[index2] - '0'; } // --- DP transformation (“SOS DP in base 3”) --- // Instead of the reverse j/while–loop, we iterate over every digit position. // For each position i (0 <= i < n-m) and each state j, if the digit at position i is nonzero, // add dp[j] to the dp state where that digit is decreased. for (int i = 0; i < (n - m); i++){ for (int j = 0; j < dpSize; j++){ int d = (j / three[i]) % 3; // digit at position i if (d > 0) dp[j - d * three[i]] += dp[j]; } } // Process each query: check whether the lower m digits of mask (precomputed in low[]) // are compatible with the current prefix (via the lookup table "valid"). If so, // add dp[high part] to the answer. for (int j = 0; j < q; j++){ if (!valid[pref][low[j]]) continue; ans[j] += dp[high[j]]; } } for (int i = 0; i < q; i++) cout << ans[i] << "\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...