题解 CF1443B 【Saving the City】

Suuon_Kanderu

2020-11-10 21:42:08

Solution

当成一个比较简单的线性 DP 入门题来做了。 首先 $dp_i$ 表示将前 i 个字符全部变为 0 的代价。 我们从前往后扫,遇到 `1` 时有两种选择: 1. 顺延最近的一个 A 操作(显然我们要从前面最近的一个 1 顺延),但我们需要把这两个 `1` 中间的 `0` 全部用 B 操作染色。 2. 另起炉灶,从这个位置开始,使用一个新的 A 操作。 还有一个注意事项,第一个 `1` 只能用一个 A 操作。 所以状态转移方程就出来了: $$ dp_i = \begin{cases} dp_{i-1} &\text{if }(s_i = 0)\\dp_{k} + \min((i - k - 1)\cdot B , A) &\text{if }(s_i=1) \end{cases} $$ (P.S. $k$ 为 $i$ 前面最近的 1 的位置, $s$ 为字符串。) ``` #include <algorithm> #include <cstdio> #include <iostream> using namespace std; const int N = 1e5 + 10; string s; int last = 0; int dp[N]; void solve() { int a , b;scanf("%d%d" , &a , &b); cin >> s; int last = 0 , i; for(i = 0; i < s.size(); i++) if(s[i] == '1') {dp[i] = a; last = i;break;} for(i++; i < s.size(); i++) { if(s[i] == '0')dp[i] = dp[i - 1]; else { dp[i] = dp[last] + min(a , (i - last - 1) * b); last = i; } } printf("%d\n" , dp[s.size() - 1]); } int main() { int t;scanf("%d" , &t); while(t--) {solve();} } ```