【BZOJ1802】[AHOI2009]checker(动态规划)

【BZOJ1802】[AHOI2009]checker(动态规划)

题面

BZOJ
洛谷

题解

首先自己观察一波,发现如果有相邻两个格子都是红色的话,那么显然可以在任意位置都存在一个跳棋。可以让两个位置反复互相跳就好了。这样子第一问的答案显然就是(0),否则的话第一问的答案就是偶数位置上(0)的个数。
如果没有相邻的两个位置都是红格子,我们还可以得出第二问的答案就是偶数位置上红格子的数目。
现在有两个红格子相邻,设(f[i])表示在(i)这个位置要出现一个棋子的最小加入的跳棋数目,显然可以暴力(dp)。那么最终的答案就是所有偶数位置上的(f)的和。

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<vector>
using namespace std;
#define ll long long
#define MAX 1010
inline int read()
{
	int x=0;bool t=false;char ch=getchar();
	while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
	if(ch=='-')t=true,ch=getchar();
	while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
	return t?-x:x;
}
int n,a[MAX];ll f[MAX];bool fl;
int main()
{
	n=read();
	for(int i=1;i<=n;++i)a[i]=read();
	for(int i=3;i<=n;++i)
		if(a[i]&&a[i-1])fl=true;
	if(!fl)
	{
		int s[2]={0,0};
		for(int i=2;i<=n;i+=2)s[a[i]]+=1;
		printf("%d
%d
",s[0],s[1]);
		return 0;
	}
	puts("0");memset(f,63,sizeof(f));
	for(int i=2;i<=n;++i)if(a[i])f[i]=1;
	for(int i=2;i<n;++i)
		if(a[i]&&a[i+1])
		{
			for(int j=i-1;j>1;--j)f[j]=min(f[j],f[j+1]+f[j+2]);
			for(int j=i+2;j<=n;++j)f[j]=min(f[j],f[j-1]+f[j-2]);
		}
	ll ans=0;
	for(int i=2;i<=n;i+=2)ans+=f[i];
	printf("%lld
",ans);
	return 0;
}
原文地址:https://www.cnblogs.com/cjyyb/p/9795214.html