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.
For a fixed completed string, compare Chell's chosen segment against declaring every cake real. A segment only helps by the amount #F inside - #T inside.
Encode a completed string with weights: +1 for F, -1 for T. Chell's best segment is exactly the maximum subarray sum, with 0 allowed for the empty segment.
If the completed string has f fake cakes and maximum subarray sum M, then Chell is forced to make f - M mistakes. GLaDOS wants to maximize that value.
So the game is not just make many cakes fake. If all fake cakes clump together, Chell catches them with one segment and you get cooked. You want many Fs while keeping every interval's balance small.
Scan left to right with Kadane-style DP. State by f = number of F chosen so far and cur = current nonnegative suffix gain; store the smallest maximum gain seen. At the end maximize f - bestM[f].
Key Translation
For a completed string, suppose Chell declares interval [l,r] as fake. The mistakes are:
F outside [l,r] + T inside [l,r].
Let F_total be the total number of fake cakes. Then:
mistakes = F_total - F_inside + T_inside = F_total - (F_inside - T_inside).
So Chell is trying to maximize F_inside - T_inside, because that subtracts from her mistake count.
Now assign each position a weight:
+1 if the cake is F-1 if the cake is TFor any interval, F_inside - T_inside is just the sum of weights in that interval. Chell's best possible improvement is the maximum subarray sum. She can also choose the empty fake segment, which gives improvement 0, so we use the nonnegative maximum subarray sum.
Therefore, for a completed string:
forced mistakes = number_of_F - maximum_subarray_sum.
That is the whole problem wearing a fake mustache.
What GLaDOS Controls
For each N, GLaDOS chooses either T or F. After all choices, two things matter:
f: how many positions became FM: the maximum subarray sum of the +1/-1 arrayThe value is f - M.
A tempting but false idea is to make every N fake. That can be awful, because if the fake cakes form one big juicy block, Chell picks that block and makes few or zero mistakes. GLaDOS wants fake cakes spread out enough that every interval has limited gain.
DP State
We process the string from left to right and simulate Kadane's algorithm.
For a fixed completed prefix, Kadane keeps:
cur: best nonnegative suffix sum ending at the current positionbest: maximum subarray sum seen anywhere in the prefixWhen we add an F, its weight is +1:
cur becomes cur + 1, and best may increase.
When we add a T, its weight is -1:
cur becomes max(0, cur - 1), and best cannot increase.
Now add uncertainty. Define:
dp[f][cur] = the minimum possible best maximum-subarray value after the processed prefix, using exactly f fake cakes, with current suffix gain cur.
If a state is impossible, it is infinity.
Transitions
At position i, depending on s[i], we may place F, T, or both.
If we place F:
nf = f + 1ncur = cur + 1nbest = max(best, ncur)If we place T:
nf = fncur = max(0, cur - 1)nbest = bestFor each resulting (nf, ncur), keep the smallest nbest.
This works because once f, cur, and best are known, the future does not care about the exact earlier string. And if two states have the same f and cur, the one with smaller best is always at least as good. No hidden drama.
Getting The Answer
After processing all positions, for each possible total fake count f, compute:
bestM[f] = min over cur of dp[f][cur].
This is the smallest maximum-subarray sum GLaDOS can force while using exactly f fake cakes. The best guaranteed mistake count for that f is:
f - bestM[f].
So the final answer is:
max over f of (f - bestM[f]).
Correctness Proof
First, for any fixed completed string, Chell's mistake count for interval [l,r] equals F_total - sum(l,r), where sum(l,r) uses +1 for F and -1 for T. Chell chooses the interval with maximum sum, or the empty interval with sum 0. Thus the minimum mistakes for that completed string are exactly F_total - M, where M is the nonnegative maximum subarray sum.
Second, the DP correctly tracks all relevant information about a partially completed prefix. Kadane's update only needs the current nonnegative suffix sum cur and the best maximum subarray sum already seen. The count f is also needed because the final score uses the total number of fake cakes. Therefore every possible completion of the prefix is represented by some DP state, and every DP transition corresponds to choosing a legal character for the next position.
Third, storing only the minimum best for each (f, cur) is safe. If two prefixes have the same f and cur, then all future updates affect them identically except that the prefix with smaller best can never become worse. So larger best is dominated and can be discarded.
Finally, for each final fake count f, the DP gives the smallest achievable M. Since the score is f - M, that is the best score GLaDOS can get with that fake count. Taking the maximum over all f gives exactly the optimal answer.
Complexity
There are O(n^2) states and n positions, so each test case runs in O(n^3) time and uses O(n^2) memory. The statement guarantees the total n^3 is small enough, so this fits cleanly.
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
void setIO() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
}
int main() {
setIO();
int tc;
cin >> tc;
const int INF = 1e9;
while (tc--) {
int n;
string s;
cin >> n >> s;
int w = n + 1;
vector<int> dp(w * w, INF), ndp(w * w, INF);
dp[0] = 0;
for (int i = 0; i < n; i++) {
fill(ndp.begin(), ndp.end(), INF);
char ch = s[i];
for (int f = 0; f <= i; f++) {
for (int cur = 0; cur <= i; cur++) {
int best = dp[f * w + cur];
if (best == INF) continue;
if (ch == 'F' || ch == 'N') {
int nf = f + 1;
int ncur = cur + 1;
int nbest = max(best, ncur);
int &cell = ndp[nf * w + ncur];
cell = min(cell, nbest);
}
if (ch == 'T' || ch == 'N') {
int ncur = max(0, cur - 1);
int &cell = ndp[f * w + ncur];
cell = min(cell, best);
}
}
}
dp.swap(ndp);
}
int ans = 0;
for (int f = 0; f <= n; f++) {
int bestM = INF;
for (int cur = 0; cur <= n; cur++) {
bestM = min(bestM, dp[f * w + cur]);
}
if (bestM != INF) ans = max(ans, f - bestM);
}
cout << ans << '\n';
}
}#include <bits/stdc++.h>
using namespace std;
using ll = long long;
void setIO() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
}
int main() {
setIO();
int tc;
cin >> tc;
const int INF = 1e9;
while (tc--) {
int n;
string s;
cin >> n >> s;
int w = n + 1;
vector<int> dp(w * w, INF), ndp(w * w, INF);
dp[0] = 0;
for (int i = 0; i < n; i++) {
fill(ndp.begin(), ndp.end(), INF);
char ch = s[i];
for (int f = 0; f <= i; f++) {
for (int cur = 0; cur <= i; cur++) {
int best = dp[f * w + cur];
if (best == INF) continue;
if (ch == 'F' || ch == 'N') {
int nf = f + 1;
int ncur = cur + 1;
int nbest = max(best, ncur);
int &cell = ndp[nf * w + ncur];
cell = min(cell, nbest);
}
if (ch == 'T' || ch == 'N') {
int ncur = max(0, cur - 1);
int &cell = ndp[f * w + ncur];
cell = min(cell, best);
}
}
}
dp.swap(ndp);
}
int ans = 0;
for (int f = 0; f <= n; f++) {
int bestM = INF;
for (int cur = 0; cur <= n; cur++) {
bestM = min(bestM, dp[f * w + cur]);
}
if (bestM != INF) ans = max(ans, f - bestM);
}
cout << ans << '\n';
}
}