ABC365D 题解
赛时脑抽了没写出来。赛后一听说是 DP 就秒了 /wul
为方便,我们用数字代替字母,用 \(1\) 表示石头(R),\(2\) 表示剪刀(S),\(3\) 表示布(P)。同时定义函数 \(\text{ne}(j) = j \mod 3 +1\),则有 \(\text{ne}(a) = b \Leftrightarrow \text{出}\ a\ \text{能赢过出}\ b\) 。
定义一下状态。用 \(f_{i, j} (1 \le j \le 3)\) 表示“考虑前 \(i\) 位,且当第 \(i\) 位出 石头/剪刀/布 时赢得的最多场次“。
我们发现用上述状态可以很轻易地转移。我们可以通过前一位出的与当前出的不同的两种状态转移之。
有:
\[f_{i, j} = \max\{f_{i-1, \text{ne}(j)}, f_{i-1, \text{ne}(\text{ne}(j))}\} + [\text{ne}(j) = s_i]
\]
然后就做完了。记得先将 \(s\) 数组的字母转成数字。时间复杂度 \(O(n)\)。
#include <iostream>
#include <cstdio>
#include <map>
using namespace std;
#define int long long
const int N = 200010;
int n, f[N][5]; string s;
map<char, int> mp;
int ne(int x) {return x % 3 + 1;}
signed main() {
cin >> n >> s; s = ' ' + s;
mp['R'] = 1, mp['S'] = 2, mp['P'] = 3;
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= 3; j++) {
if(ne(mp[s[i]]) == j) continue;
f[i][j] = max(f[i - 1][ne(j)], f[i - 1][ne(ne(j))]);
if(ne(j) == mp[s[i]]) f[i][j]++;
}
}
int ans = 0;
for (int j = 1; j <= 3; j++) ans = max(ans, f[n][j]);
cout << ans;
return 0;
}

浙公网安备 33010602011771号