Search for a command to run...
Progressive hints first, then the full explanation and implementation when you're ready to cash out.
Review status
AI-generated and still unreviewed. Double-check the details before internalizing them.
Hints
Open only as much as you need to keep the solve alive.
The recurrence looks path-dependent, but try searching for a potential function. You want some expression whose difference from contains .
Use . For both possible transitions, check that Same formula for 0 and 1; that is the whole trick.
After summing over all , the answer for a completed string depends only on its final value : So now the job is only to find all reachable final values.
Every reachable value belongs to one of four affine families: Operation 0 shifts the index by or , while operation 1 swaps between these families.
Keep four bitsets for those four families. For each character, OR in the transitions allowed by 0 and/or 1, sync the duplicate states for and , then convert all reachable final values through the formula and sort/unique the resulting sums.
The problem is not asking for the sum over completions. It asks for the sum of distinct possible values of . That distinction matters; counting completions is the classic trap here, and it gets you cooked.
The first useful move is to stop trying to track the whole generating array. Define
For a 0 transition, :
For a 1 transition, :
Beautifully, both cases give the same identity. Summing over gives
Since and ,
so
That means a completed string's entire sum is determined only by its final value . The problem becomes: find all possible final values , map them through this formula, remove duplicates, and sum them.
Now we need a compact reachable-set DP for .
Starting from , every reachable value can be represented in one of these four forms:
where . After at most operations, we only need .
Maintain four bitsets:
Initially, is reachable, so set and .
If the next chosen character is 0, then :
So the positive-family bitsets shift left, and the negative-family bitsets shift right.
If the next chosen character is 1, then :
So this operation just swaps between the four families.
There is one annoying boundary detail: has two names, and , and has two names, and . After every step, sync those pairs. This avoids special-casing shifts from index .
For a fixed character:
1, apply the 0 transitions.0, apply the 1 transitions.So ? simply applies both and unions the results.
At the end, enumerate all marked states, reconstruct their represented , compute
sort the resulting values, remove duplicates, and sum modulo .
Why deduplicate after computing , not only after computing ? Because the quadratic can map two different final values to the same sum. Also, the four-family representation itself can contain duplicate numeric values when and have special relationships. Sorting the final values is the blunt and correct fix.
The numerator can exceed 64-bit while computing , so use __int128. The final itself fits in signed 64-bit under the constraints, but the intermediate square does not always play nice.
Complexity: each transition uses a constant number of bitset shifts and ORs over bits. With word-level bitset operations, this is
per large test in practice, and the total over all tests is . Memory is bits per bitset, i.e. tiny.
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
void setIO() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
}
const int MAXN = 100001;
const ll MOD = 998244353;
using i128 = __int128_t;
using Bits = bitset<MAXN>;
ll valueSum(int n, ll x, ll y, ll c) {
i128 num = (i128)c * c + (i128)(x - y) * c + (i128)n * x * y;
return (ll)(num / (2 * (i128)x));
}
void solve() {
int n;
ll x, y;
string s;
cin >> n >> x >> y >> s;
Bits a0, a1, b0, b1;
a0.set(0);
b0.set(0);
for (char ch : s) {
Bits na0, na1, nb0, nb1;
if (ch != '1') {
na0 |= a0 << 1;
na1 |= a1 << 1;
nb0 |= b0 >> 1;
nb1 |= b1 >> 1;
}
if (ch != '0') {
na0 |= b1;
na1 |= b0;
nb0 |= a1;
nb1 |= a0;
}
bool zero = na0[0] || nb0[0];
na0[0] = nb0[0] = zero;
bool yval = na1[0] || nb1[0];
na1[0] = nb1[0] = yval;
a0 = na0;
a1 = na1;
b0 = nb0;
b1 = nb1;
}
vector<ll> vals;
vals.reserve(4 * n + 4);
for (int i = 0; i <= n; i++) {
if (a0[i]) vals.push_back(valueSum(n, x, y, (ll)i * x));
if (a1[i]) vals.push_back(valueSum(n, x, y, (ll)i * x + y));
}
for (int i = 1; i <= n; i++) {
if (b0[i]) vals.push_back(valueSum(n, x, y, -(ll)i * x));
if (b1[i]) vals.push_back(valueSum(n, x, y, -(ll)i * x + y));
}
sort(vals.begin(), vals.end());
vals.erase(unique(vals.begin(), vals.end()), vals.end());
ll ans = 0;
for (ll v : vals) {
ans = (ans + v % MOD + MOD) % MOD;
}
cout << ans << '\n';
}
int main() {
setIO();
int t;
cin >> t;
while (t--) solve();
}#include <bits/stdc++.h>
using namespace std;
using ll = long long;
void setIO() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
}
const int MAXN = 100001;
const ll MOD = 998244353;
using i128 = __int128_t;
using Bits = bitset<MAXN>;
ll valueSum(int n, ll x, ll y, ll c) {
i128 num = (i128)c * c + (i128)(x - y) * c + (i128)n * x * y;
return (ll)(num / (2 * (i128)x));
}
void solve() {
int n;
ll x, y;
string s;
cin >> n >> x >> y >> s;
Bits a0, a1, b0, b1;
a0.set(0);
b0.set(0);
for (char ch : s) {
Bits na0, na1, nb0, nb1;
if (ch != '1') {
na0 |= a0 << 1;
na1 |= a1 << 1;
nb0 |= b0 >> 1;
nb1 |= b1 >> 1;
}
if (ch != '0') {
na0 |= b1;
na1 |= b0;
nb0 |= a1;
nb1 |= a0;
}
bool zero = na0[0] || nb0[0];
na0[0] = nb0[0] = zero;
bool yval = na1[0] || nb1[0];
na1[0] = nb1[0] = yval;
a0 = na0;
a1 = na1;
b0 = nb0;
b1 = nb1;
}
vector<ll> vals;
vals.reserve(4 * n + 4);
for (int i = 0; i <= n; i++) {
if (a0[i]) vals.push_back(valueSum(n, x, y, (ll)i * x));
if (a1[i]) vals.push_back(valueSum(n, x, y, (ll)i * x + y));
}
for (int i = 1; i <= n; i++) {
if (b0[i]) vals.push_back(valueSum(n, x, y, -(ll)i * x));
if (b1[i]) vals.push_back(valueSum(n, x, y, -(ll)i * x + y));
}
sort(vals.begin(), vals.end());
vals.erase(unique(vals.begin(), vals.end()), vals.end());
ll ans = 0;
for (ll v : vals) {
ans = (ans + v % MOD + MOD) % MOD;
}
cout << ans << '\n';
}
int main() {
setIO();
int t;
cin >> t;
while (t--) solve();
}