Loading

Codeforces Round 978 (Div. 2) C. Gerrymandering

算法

题意是清楚的, 我们注意到, 类似于这种框图问题, 考虑使用轮廓线 \(\rm{dp}\)

首先要确定几种情况, 观察样例就可以知道, 分割完一个选区之后, 只有这几种情况

pA505aF.png

所以我们记录 \(s\) 表示当前决策点处轮廓线长什么样 , \(i\) 表示这是决策点是第几列(?) , 就有定义 \(f_{i, s}\) , 其中

\[s \in \left\{ \left [ \begin{array}{} 1 & 1 \\ 1 & 0 \\ \end{array} \right ] , \left [ \begin{array}{} 1 & 0 \\ 1 & 0 \\ \end{array} \right ] , \left [ \begin{array}{} 1 & 0 \\ 1 & 1 \\ \end{array} \right ] \right\} \]

分别记为 \(s_1, s_2, s_3\)

考虑 \(\rm{dp}\) 方程

首先是状态的变动, 我们分类讨论

在上面加上三横排,
同样的, 必须要在下面加

\[\left [ \begin{array}{} 1 & 1 \\ 1 & 0 \\ \end{array} \right ] \Rightarrow \left [ \begin{array}{} 1 & 1 \\ 1 & 0 \\ \end{array} \right ] \]

\[\left [ \begin{array}{} 1 & 0 \\ 1 & 1 \\ \end{array} \right ] \Rightarrow \left [ \begin{array}{} 1 & 0 \\ 1 & 1 \\ \end{array} \right ] \]

\[\left [ \begin{array}{} 1 & 0 \\ 1 & 0 \\ \end{array} \right ] \Rightarrow \left [ \begin{array}{} 1 & 0 \\ 1 & 0 \\ \end{array} \right ] \]

其实就是保持不变

\[f_{i, s} \gets f_{i - 3, s} \]


对于

\[\left [ \begin{array}{} 1 & 0 \\ 1 & 0 \\ \end{array} \right ] \]

可以加上一个
pA5BlMq.png

变成这个

\[\left [ \begin{array}{} 1 & 0 \\ 1 & 1 \\ \end{array} \right ] \]

\[f_{i, s_3} \gets f_{i - 1, s_2} \]


对于

\[\left [ \begin{array}{} 1 & 0 \\ 1 & 1 \\ \end{array} \right ] \]

可以加上一个

pA5BDL6.png

变成

\[\left [ \begin{array}{} 1 & 0 \\ 1 & 0 \\ \end{array} \right ] \]

\[f_{i, s_2} \gets f_{i - 2, s_3} \]


对于

\[\left [ \begin{array}{} 1 & 1 \\ 1 & 0 \\ \end{array} \right ] \]

pA5BseK.png

变成

\[\left [ \begin{array}{} 1 & 0 \\ 1 & 0 \\ \end{array} \right ] \]

\[f_{i, s_2} \gets f_{i - 2, s_1} \]


对于

\[\left [ \begin{array}{} 1 & 0 \\ 1 & 0 \\ \end{array} \right ] \]

pA5BqYQ.png

变成

\[\left [ \begin{array}{} 1 & 1 \\ 1 & 0 \\ \end{array} \right ] \]

\[f_{i, s_1} \gets f_{i - 1, s_2} \]


总结一下, 方程为
(\(res\) 表示是否投票)

\[\begin{cases} \begin{aligned} & dp_{i, 1 / 2 / 3} \gets dp_{i - 3, 1 / 2 / 3} + res\\ & dp_{i, 2} \gets dp_{i - 2, 3} + res\\ & dp_{i, 3} \gets dp_{i - 1, 2} + res\\ & dp_{i, 1} \gets dp_{i - 1, 2} + res\\ & dp_{i, 2} \gets dp_{i - 2, 1} + res\\ \end{aligned} \end{cases} \]

取最大值即可, 答案即为 \(f_{n + 1, 2}\)

复杂度 \(\mathcal{O}(n)\)

代码

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mod = 1e9 + 7;
const int N = 2e5 + 20;
ll a[N], b[N];
ll dp[N][4];

int main()
{
    int t;
    cin >> t;
    while (t--)
    {
        int n;
        cin >> n;
        for (int i = 1; i <= n; i++)
        {
            char x;
            cin >> x;
            a[i] = (x == 'A');
        }
        for (int i = 1; i <= n; i++)
        {
            char x;
            cin >> x;
            b[i] = (x == 'A');
        }

        dp[1][2] = 0;
        // 1 上. 3 下
        for (int i = 2; i <= n + 1; i++)
        {
            dp[i][1] = dp[i][2] = dp[i][3] = 0;
            if (i >= 4)
            {
                dp[i][2] = max(dp[i][2], dp[i - 3][2] + ((a[i - 1] + a[i - 2] + a[i - 3]) >= 2) + ((b[i - 1] + b[i - 2] + b[i - 3]) >= 2)); 
                dp[i][1] = max(dp[i][1], dp[i - 3][1] + ((a[i] + a[i - 1] + a[i - 2]) >= 2) + ((b[i - 1] + b[i - 2] + b[i - 3]) >= 2)); 
                dp[i][3] = max(dp[i][3], dp[i - 3][3] + ((a[i - 1] + a[i - 2] + a[i - 3]) >= 2) + ((b[i] + b[i - 1] + b[i - 2]) >= 2)); 
            }

            if (i >= 3)
            {
                dp[i][2] = max(dp[i][2], dp[i - 2][3] + ((a[i - 1] + a[i - 2] + b[i - 1]) >= 2)); 
                dp[i][2] = max(dp[i][2], dp[i - 2][1] + ((a[i - 1] + b[i - 1] + b[i - 2]) >= 2)); 
            }

            dp[i][1] = max(dp[i][1], dp[i - 1][2] + ((a[i] + a[i - 1] + b[i - 1]) >= 2));
            dp[i][3] = max(dp[i][3], dp[i - 1][2] + ((a[i - 1] + b[i] + b[i - 1]) >= 2)); 
        }
        
        cout << dp[n + 1][2] << "\n";
    }
    return 0;
}

总结

按需分析, 挺简单的

posted @ 2024-11-29 15:57  Yorg  阅读(80)  评论(0)    收藏  举报