CF EDU 136 总结
E
如此唐氏的 DP 我居然想了这么久我是不是废了。
我们先思考一下什么情况下会崩溃。
观察到对于一个脏格子 \((i,j)\) 如果 \((3-i,j-1)\) 是脏的,那么如果扫地机移动到了 \((i,j-1)\) ,它就会崩溃。
这指向我们去维护一下下一行上下两个格子的状态,即他们是否被清理。
故我们定义 \(dp_{i,0/1,0/1,0/1}\) 表示当前停留在 \((j,i)\) 上,且 \((3-j,i)\) 如果是脏的,已被清理,第 \(i+1\) 列上下两个格子是否被清理的状态。
你考虑直接枚举 \(i-1\) 的 \(0/1\) 状态判断合法直接转移即可,细节见代码。
个人认为有一篇比较好的解释
#include <bits/stdc++.h>
using namespace std;
#define maxn 200005
int n;
int a[2][maxn];
int dp[maxn][2][2][2];
bool check(int x, int y, int s0, int x0, int s1, int x1)
{
if(!x)
{
if(!y) return !x0;
else return !(x0 && s1) && x0;
}
else
{
if(!y) return !(x1 && s0) && s0;
else return !s0;
}
}
int main()
{
scanf("%d", &n);
int sum = 0;
for (int i = 0; i < 2; ++i) for (int j = 1; j <= n; ++j) scanf("%1d", &a[i][j]), sum += a[i][j];
memset(dp, 0x3f, sizeof(dp));
dp[0][0][0][0] = 0, dp[0][0][0][1] = dp[0][0][1][0] = 1, dp[0][0][1][1] = 2;
for (int i = 1; i <= n; ++i)
{
for (int j = 0; j < 2; ++j)
{
for (int k = 0; k < 2; ++k)
{
for (int l = 0; l < 2; ++l)
{
for (int J = 0; J < 2; ++J)
{
for (int K = 0; K < 2; ++K)
{
for (int L = 0; L < 2; ++L)
{
if(check(j, J, (k ? 0 : a[0][i]), (l ? 0 : a[1][i]), (K ? 0 : a[0][i + 1]), (L ? 0 : a[1][i + 1])))
dp[i][J][K][L] = min(dp[i][J][K][L], dp[i - 1][j][k][l] + K + L);
}
}
}
}
}
}
}
cout << sum - min(dp[n][0][0][0], dp[n][1][0][0]) << endl;
return 0;
}

浙公网安备 33010602011771号