Codeforces Round 978 (Div. 2) C. Gerrymandering
算法
题意是清楚的, 我们注意到, 类似于这种框图问题, 考虑使用轮廓线 \(\rm{dp}\)
首先要确定几种情况, 观察样例就可以知道, 分割完一个选区之后, 只有这几种情况
所以我们记录 \(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 ]
\]
变成这个
\[\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 ]
\]
可以加上一个
变成
\[\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 ]
\]
变成
\[\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 ]
\]
变成
\[\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;
}
总结
按需分析, 挺简单的






浙公网安备 33010602011771号