dp1

题目: Cake Trial

题目背景

GLaDOS 为 Chell 设计了一项测试。有 n 个蛋糕排成一行,每个蛋糕可能是真的(T)或假的(F)。Chell 可以准确判断每个蛋糕的真假,但她的回答必须满足:所有她认为是假的蛋糕必须形成一个连续的子段(可以为空)

题目描述

初始时,GLaDOS 已经放置了一些蛋糕,但有些位置尚未确定,用字符 N 表示。GLaDOS 可以自由地将每个 N 替换为 TF,以最大化 Chell 被迫犯的错误数
Chell 在看到最终排列后,会选择一段连续区间作为她声称的假蛋糕集合(区间外都视为真),并最小化错误数

请你计算 GLaDOS 能保证的最大错误数

输入格式

  • 第一行:一个整数 t(1 ≤ t ≤ 10⁴),表示测试用例数。
  • 每个测试用例:
    • 第一行:一个整数 n(1 ≤ n ≤ 500),表示蛋糕数量。
    • 第二行:一个长度为 n 的字符串 s,由字符 TFN 组成。

数据保证:所有测试用例的 之和不超过 500³

输出格式

对于每个测试用例,输出一个整数 —— GLaDOS 能保证的最大错误数。

核心思路(简要)

  • 若 Chell 选择区间 [l, r],则错误数
    M = F_total - (F_in - T_in),其中 F_total 为总假蛋糕数,F_inT_in 为区间内假/真蛋糕数。
  • F 看作 +1T 看作 -1,则 F_in - T_in 就是区间和。Chell 要最小化 M,等价于最大化区间和,即最大子段和 Smax(允许空区间,故 Smax ≥ 0)。
  • 因此,对于固定排列,Chell 的最小错误数为 F_total - Smax
  • GLaDOS 要最大化该值,即填充所有 N 后使 F_total - Smax 最大。
  • 采用三维 DP:
    • 状态 dp[i][f][s]:处理完前 i 个位置,总假数为 f,以 i 结尾的最大子段和为 s 时,全局最大子段和 Smax 的最小可能值
    • 转移:根据当前位置放 FT 更新 fsSmax
    • 最终答案:max_{f, s} ( f - dp[n][f][s] )
  • 时间复杂度 O(n³),满足题目限制。
  • 题目链接:https://codeforces.com/contest/2238/problem/E
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
const int INF = 1e9;

void solve() {
    int n; string s; cin >> n >> s;
    vector<vector<int>> dp(n + 1, vector<int>(n + 1, INF));
    dp[0][0] = 0;
    for(int i = 0; i < n; i ++) {
        vector<vector<int>> ndp(n + 1, vector<int>(n + 1, INF));
        char ch = s[i];
        for(int f = 0; f <= i; f ++) {
            for(int cur = 0; cur <= i; cur ++) {
                if(dp[f][cur] == INF) continue;
                if(ch == 'F' || ch == 'N') {
                    int nf = f + 1;
                    int ncur = cur + 1;
                    int maxv = max(dp[f][cur], ncur);
                    ndp[nf][ncur] = min(ndp[nf][ncur], maxv);
                }
                if(ch == 'T' || ch == 'N') {
                    int nf = f;
                    int ncur = max(0, cur - 1);
                    int maxv = dp[f][cur];
                    ndp[nf][ncur] = min(ndp[nf][ncur], maxv);
                }
            }
        }
        dp.swap(ndp);
    }
    int ans = 0;
    for(int f = 0; f <= n; f ++) {
        for(int cur = 0; cur <= n; cur ++) {
            if(dp[f][cur] != INF) ans = max(ans, f - dp[f][cur]);
        }
    }
    cout << ans << '\n';
}

int main() {
    ios::sync_with_stdio(false); cin.tie(0);
    int t; cin >> t;
    while(t --) solve();
    return 0;
}
 
posted @ 2026-08-26 10:28  thenrify  阅读(2)  评论(0)    收藏  举报