题解:洛谷 AT_abc464_d Celester

【题目来源】

洛谷:AT_abc464_d [ABC464D] Celester - 洛谷

【题目描述】

The weather for the upcoming \(N\) days is given as a string \(S\).
If the \(i\)-th character of \(S\) is S, then the weather on day \(i\) is sunny; if it is R, then the weather on day \(i\) is rainy.
Also, your current happiness is \(0\).

You can perform the following operation any number of times, possibly zero:

  • Choose an integer \(i\) with \(1 \le i \le N\).
  • If the weather on day \(i\) is sunny, change it to rainy; if it is rainy, change it to sunny.
  • However, if you change the weather on day \(i\), your happiness decreases by \(X_i\).

After performing the operations, your happiness increases based on the final weather according to the following condition:

  • For each integer \(i\) with \(1 \le i \le N-1\), if the weather on day \(i\) after modification is rainy and the weather on day \(i+1\) is sunny, your happiness increases by \(Y_i\).

Find the maximum value of happiness achievable by performing operations.

\(T\) test cases are given; solve each.

未来 \(N\) 天的天气由一个字符串 \(S\) 给出。
如果 \(S\) 的第 \(i\) 个字符是 S,则第 \(i\) 天的天气是晴天;如果是 R,则第 \(i\) 天的天气是雨天。
此外,你当前的幸福值为 \(0\)

你可以执行以下操作任意次数(也可以零次):

  • 选择一个整数 \(i\),满足 \(1 \le i \le N\)
  • 如果第 \(i\) 天的天气是晴天,则将其改为雨天;如果是雨天,则将其改为晴天。
  • 但是,如果你改变第 \(i\) 天的天气,你的幸福值会减少 \(X_i\)

执行操作后,根据最终天气,你的幸福值会按以下条件增加:

  • 对于每个满足 \(1 \le i \le N-1\) 的整数 \(i\),如果修改后第 \(i\) 天的天气是雨天且第 \(i+1\) 天的天气是晴天,你的幸福值会增加 \(Y_i\)

求通过执行操作可达到的最大幸福值。

给定 \(T\) 组测试用例,请分别求解。

【输入】

The input is given from Standard Input in the following format, where \(\mathrm{case}_i\) denotes the \(i\)-th test case:

\(T\)
\(\mathrm{case}_1\)
\(\mathrm{case}_2\)
\(\vdots\)
\(\mathrm{case}_T\)

Each test case is given in the following format:

\(N\)
\(S\)
\(X_1\) \(X_2\) \(\dots\) \(X_N\)
\(Y_1\) \(Y_2\) \(\dots\) \(Y_{N-1}\)

【输出】

Output \(T\) lines. The \(i\)-th line should contain the answer for the \(i\)-th test case.

【输入样例】

5
6
SRRRSR
3 1 4 1 5 9
2 6 5 3 5
6
RSRSRS
10 10 10 10 10 10
1 1 1 1 1
2
RR
4 3
2
10
RSSRSSRSSR
75 49 79 37 16 9 38 49 69 54
23 100 73 63 66 23 51 65 67
20
SSSRSSSRRRRSSRSSRSSR
343191362 223147518 135066250 426658267 693515093 8023388 383375974 712283203 40447501 19870690 318452142 356265717 283999278 209219229 418603824 39363351 392058270 254796273 110117486 64951139
576697130 385986330 895027325 654885799 784214084 577658764 761714876 583039741 943991250 446493376 701505924 402891440 963636095 919408713 238125227 871191978 843843821 397910552 529447424

【输出样例】

5
3
0
165
5201284760

【核心思想】

  1. 问题分析:给定 \(N\) 天的初始天气字符串 \(S\)S 表示晴天,R 表示雨天),每天 \(i\) 改变天气需付出代价 \(X_i\)。最终天气中,若相邻两天出现"第 \(i\) 天雨天且第 \(i+1\) 天晴天"的组合,则获得收益 \(Y_i\)。目标是最大化总幸福值。关键观察是:每天只有两种状态(雨天/晴天),且第 \(i\) 天的收益仅依赖于第 \(i-1\) 天和第 \(i\) 天的状态组合,具有无后效性

  2. 算法选择

    • 线性动态规划(一维状态扩展):定义 \(dp[i][state]\) 表示处理到第 \(i\) 天、第 \(i\) 天天气为 \(state\) 时的最大幸福值
    • 状态压缩:每天只有两种天气状态,用 \(0\) 表示雨天(R),\(1\) 表示晴天(S
  3. 关键步骤

    • 初始化\(dp[1][orig] = 0\)(不改变第 \(1\) 天天气),\(dp[1][orig \oplus 1] = -X_1\)(改变第 \(1\) 天天气),其中 \(orig\) 为第 \(1\) 天的原始天气
    • 状态转移(枚举第 \(i\) 天的状态 \(j \in \{0, 1\}\)):
      • 计算改变代价:若 \(j = orig_i\)(与原始天气相同),代价为 \(0\);否则为 \(-X_i\)
      • 枚举第 \(i-1\) 天的状态 \(k \in \{0, 1\}\)
        • \(k = 0\)\(j = 1\)(即第 \(i-1\) 天雨天、第 \(i\) 天晴天),获得收益 \(+Y_{i-1}\)
        • 状态转移:\(dp[i][j] = \max(dp[i][j], dp[i-1][k] + cost + gain)\)
    • 输出答案\(\max(dp[N][0], dp[N][1])\)
  4. 时间/空间复杂度

    • 时间复杂度:\(O(T \cdot N \cdot 4) = O(TN)\),每个测试用例中每天的状态转移为 \(2 \times 2 = 4\) 种组合
    • 空间复杂度:\(O(N)\),滚动数组可优化至 \(O(1)\)
  5. 线性动态规划的核心思想

    • 状态定义聚焦关键信息\(dp[i][j]\) 只记录第 \(i\) 天的天气状态,因为第 \(i+1\) 天的收益仅取决于第 \(i\) 天的状态,更早的历史不影响未来决策
    • 局部最优推全局最优:通过枚举相邻两天的所有状态组合(共 \(4\) 种),确保每个转移都是当前最优选择,利用最优子结构性质
    • 代价与收益分离处理:将"改变天气的代价"(单点决策)和"相邻组合的收益"(边决策)分开计算,清晰体现在转移方程中
    • 初始状态完整性:第 \(1\) 天同时考虑"改变"和"不改变"两种可能,避免遗漏最优解
    • 适用于序列决策问题,尤其是每天/每步的选择有限且未来收益仅依赖当前状态的场景

【算法标签】

普及 #线性DP-一维

【代码详解】

#include <bits/stdc++.h>
using namespace std;
#define int long long           // 将 int 定义为 long long,防止数值溢出
const int N = 200005;           // 最大天数
int T, n;                       // T: 测试用例数, n: 天数
string s;                       // s: 天气字符串(1-indexed,s[1]表示第1天)
int x[N], y[N];                 // x[i]: 改变第i天天气的幸福值代价, y[i]: 第i天雨且第i+1天晴的增益
// dp[i][0]: 第i天为雨天(R)时的最大幸福值
// dp[i][1]: 第i天为晴天(S)时的最大幸福值
int dp[N][2];

signed main()                   // 使用 signed 替代 int,因为 #define int long long
{
    cin >> T;                   // 读入测试用例数
    while (T--)                 // 依次处理每个测试用例
    {
        cin >> n >> s;          // 读入天数和天气字符串
        s = " " + s;            // 转换为1-indexed,s[1]表示第1天

        // 读入改变每天天气的代价
        for (int i = 1; i <= n; i++)
            cin >> x[i];

        // 读入相邻天天气组合的收益
        for (int i = 1; i < n; i++)
            cin >> y[i];

        // 初始化DP数组为负无穷
        for (int i = 0; i <= n; i++)
            dp[i][0] = dp[i][1] = -1e18;

        // 第1天的初始状态
        int orig = (s[1] == 'S') ? 1 : 0;   // orig=1表示原天气是S,orig=0表示原天气是R

        // 不改变第1天天气:幸福值为0
        dp[1][orig] = 0;
        // 改变第1天天气:幸福值减少x[1]
        dp[1][orig ^ 1] = -x[1];

        // 从第2天开始DP
        for (int i = 2; i <= n; i++)
        {
            int orig = (s[i] == 'S') ? 1 : 0;   // 第i天原天气

            // 枚举第i天的最终天气j(0=R,1=S)
            for (int j = 0; j < 2; j++)
            {
                // 改变天气的代价:如果j等于原天气,代价为0;否则减少x[i]
                int cost = (j == orig) ? 0 : -x[i];

                // 枚举第i-1天的天气k
                for (int k = 0; k < 2; k++)
                {
                    int gain = 0;   // 相邻天气组合的收益

                    // 如果第i-1天是R(0)且第i天是S(1),获得收益y[i-1]
                    if (k == 0 && j == 1)
                        gain = y[i - 1];

                    // 状态转移:从第i-1天的状态k转移到第i天的状态j
                    dp[i][j] = max(dp[i][j], dp[i - 1][k] + cost + gain);
                }
            }
        }

        // 输出答案:第n天为R或S的最大幸福值
        cout << max(dp[n][0], dp[n][1]) << endl;
    }

    return 0;
}

【运行结果】

5
6
SRRRSR
3 1 4 1 5 9
2 6 5 3 5
5
6
RSRSRS
10 10 10 10 10 10
1 1 1 1 1
3
2
RR
4 3
2
0
10
RSSRSSRSSR
75 49 79 37 16 9 38 49 69 54
23 100 73 63 66 23 51 65 67
165
20
SSSRSSSRRRRSSRSSRSSR
343191362 223147518 135066250 426658267 693515093 8023388 383375974 712283203 40447501 19870690 318452142 356265717 283999278 209219229 418603824 39363351 392058270 254796273 110117486 64951139
576697130 385986330 895027325 654885799 784214084 577658764 761714876 583039741 943991250 446493376 701505924 402891440 963636095 919408713 238125227 871191978 843843821 397910552 529447424
5201284760
posted @ 2026-06-30 21:15  团爸讲算法  阅读(6)  评论(0)    收藏  举报