CF2022C Gerrymandering

//记录一下思考这道题dp的过程
//首先发现如果想填三个格子,填法只有那么几种。所以我在一开始的想法是设置一个多维dp,记录下当前对应第几行、已经填了多少个、以及是哪一种填法
//但是发现这样不好转移,或者说无法转移。那么再思考,其实考虑填法的那一维可以变成当前这一列对应的两个格子各自的状态,用二进制表示
//即0表示当前两个格子都不填,1表示只填上面那个,2表示只填下面那个,3表示都填
//此时状态就变成了二维,并且状态转移很简单,只需要再注意一下上下同时填横着的三个格子的情况即可
#include<bits/stdc++.h>
    
using namespace std;
    
int t;
const int N = 2e5 + 10;
int n;
string s[2];
vector<int> num;
    
void solve() {
    cin >> n >> s[0] >> s[1];
    num.assign(n + 10,0);
    vector<vector<int> > dp(n + 10,vector<int>(4));
    s[0] = " " + s[0];
    s[1] = " " + s[1];
    for(int i = 1;i <= n;i++) {
        int res = 0;
        if(s[0][i] == 'A') num[i]++;
        if(s[1][i] == 'A') num[i]++;
    }
    for(int i = 2;i <= n;i++) {
        dp[i][1] = dp[i - 2][3] + ((num[i - 1] + (s[0][i] == 'A')) >= 2);
        dp[i][2] = dp[i - 2][3] + ((num[i - 1] + (s[1][i] == 'A')) >= 2);
        dp[i][3] = max(dp[i - 1][2] + ((num[i] + (s[0][i - 1] == 'A')) >= 2),dp[i - 1][1] + ((num[i] + (s[1][i - 1] == 'A')) >= 2));
        if(i >= 3) {
            int r1 = (s[0][i] == 'A') + (s[0][i - 1] == 'A') + (s[0][i - 2] == 'A');
            int r2 = (s[1][i] == 'A') + (s[1][i - 1] == 'A') + (s[1][i - 2] == 'A');
            dp[i][3] = max(dp[i][3],dp[i - 3][3] + (r1 >= 2) + (r2 >= 2));
        }
        if(i >= 4) {
            int r1 = (s[0][i] == 'A') + (s[0][i - 1] == 'A') + (s[0][i - 2] == 'A');
            int r2 = (s[1][i] == 'A') + (s[1][i - 1] == 'A') + (s[1][i - 2] == 'A');
            int r3 = (s[0][i - 1] == 'A') + (s[0][i - 2] == 'A') + (s[0][i - 3] == 'A');
            int r4 = (s[1][i - 1] == 'A') + (s[1][i - 2] == 'A') + (s[1][i - 3] == 'A');
            dp[i][1] = max(dp[i][1],dp[i - 3][1] + (r1 >= 2) + (r4 >= 2));
            dp[i][2] = max(dp[i][2],dp[i - 3][2] + (r2 >= 2) + (r3 >= 2));
        }
    }
    cout << dp[n][3] << '\n';
}
    
signed main() {
    ios::sync_with_stdio(0);
    cin.tie(0);cout.tie(0);
    cin >> t;
    while(t--) solve();
    
    return 0;
}
posted @ 2025-04-30 19:02  孤枕  阅读(20)  评论(0)    收藏  举报