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;  
}
posted @ 2024-08-04 08:22  White_Way  阅读(41)  评论(0)    收藏  举报