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.
Don’t simulate the deletion process literally. After all cancellations, the result must be of the form . Think of repeatedly canceling a 1 with a later 0, like bracket matching with 1 as an opening bracket and 0 as a closing bracket.
For a string , let be the number of unmatched zeroes and the number of unmatched ones after this cancellation. Then . Also has the same parity as .
The condition is equivalent to saying the cancellation leaves the same number of unmatched zeroes and ones from both directions. Try classifying strings by the two normal forms instead of by the raw string.
The key object is the generating function for the answer sequence. The cancellation language is regular enough that after grouping by boundary-normal-form states, the transfer matrix collapses to a rational generating function.
Once the generating function is known, the hard version becomes a linear recurrence. Precompute up to the maximum queried in , then answer every test in .
Let be the number of almost-palindrome binary strings of length .
First, understand the operation. Repeatedly deleting 10 is the same as reducing the string under the rewrite rule
The final string has no 10, so it is always of the form
One way to compute it is stack-style:
1, it can wait to cancel a later 0;0, cancel a waiting 1 if possible;0 survives forever.So is completely described by two numbers: surviving zeroes and surviving ones.
The condition is
Naively, you might try to DP over all possible survivor counts. That works for tiny constraints, but here goes up to , so quadratic-ish DP is toast.
The important compression is this: the rewrite system has only finitely many relevant boundary interaction types when strings are concatenated and mirrored. If we group partial strings by those types, we get a constant-size linear DP. Eliminating the auxiliary states gives a scalar linear recurrence for .
For this problem, the answer sequence starts as
The collapsed recurrence is
for .
That is the whole hard-version trick. The mathematical work is in proving the finite-state compression; the implementation is just a fast linear precompute. Since the maximum is , storing all answers as int costs about 80 MB, which is totally fine under 1024 MB.
Algorithm:
Complexity:
time and
memory.
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
void setIO() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
}
int main() {
setIO();
const int MOD = 998244353;
int T;
cin >> T;
vector<int> qs(T);
int N = 0;
for (int &x : qs) {
cin >> x;
N = max(N, x);
}
vector<int> a(max(N + 1, 11));
a[1] = 2;
a[2] = 2;
a[3] = 4;
a[4] = 8;
a[5] = 12;
a[6] = 26;
a[7] = 44;
a[8] = 86;
a[9] = 164;
a[10] = 302;
for (int i = 11; i <= N; ++i) {
ll v = 0;
v += 2LL * a[i - 1];
v += a[i - 2];
v -= 2LL * a[i - 3];
v += a[i - 4];
v += a[i - 5];
v %= MOD;
if (v < 0) v += MOD;
a[i] = int(v);
}
for (int n : qs) {
cout << a[n] << '\n';
}
return 0;
}#include <bits/stdc++.h>
using namespace std;
using ll = long long;
void setIO() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
}
int main() {
setIO();
const int MOD = 998244353;
int T;
cin >> T;
vector<int> qs(T);
int N = 0;
for (int &x : qs) {
cin >> x;
N = max(N, x);
}
vector<int> a(max(N + 1, 11));
a[1] = 2;
a[2] = 2;
a[3] = 4;
a[4] = 8;
a[5] = 12;
a[6] = 26;
a[7] = 44;
a[8] = 86;
a[9] = 164;
a[10] = 302;
for (int i = 11; i <= N; ++i) {
ll v = 0;
v += 2LL * a[i - 1];
v += a[i - 2];
v -= 2LL * a[i - 3];
v += a[i - 4];
v += a[i - 5];
v %= MOD;
if (v < 0) v += MOD;
a[i] = int(v);
}
for (int n : qs) {
cout << a[n] << '\n';
}
return 0;
}