CF EDU 136 总结

E

如此唐氏的 DP 我居然想了这么久我是不是废了。

我们先思考一下什么情况下会崩溃。

观察到对于一个脏格子 (i,j) 如果 (3i,j1) 是脏的,那么如果扫地机移动到了 (i,j1) ,它就会崩溃。

这指向我们去维护一下下一行上下两个格子的状态,即他们是否被清理。

故我们定义 dpi,0/1,0/1,0/1 表示当前停留在 (j,i) 上,且 (3j,i) 如果是脏的,已被清理,第 i+1 列上下两个格子是否被清理的状态。

你考虑直接枚举 i10/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;
}
posted @   Saltyfish6  阅读(10)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
Document
点击右上角即可分享
微信分享提示