ZOJ 3747 Attack On Titan

原题链接

题意简述:

给定 N、M、K(N<=10^6),求有多少种给 N 个物品染色的方式,使得至少有一个子段满足染色为 G 的有连续 M 个,染色为 R 的至多连续 K 个。每个物品必须染色成 R、G、B 中的一种。

题意分析:

条件“至少一个子段满足有连续M个”不方便转移,可以转化为 至多有 N 个连续的的方案 减去 至多有 M-1 个连续的的方案。
那么两问统一成一个问题:求染色为 X 的至多连续 K 个的方案数。
接下来就考虑分情况讨论递推。假设当前为第 i 个物品,且之前的序列符合要求

  • 当 i < k 时。显然,无论怎么染色都没关系。
  • 当 i = k 时。显然,就是上一种情况减去唯一的一种不合法方案——全部为 X 的方案数。
  • 当 i > k 时。如果此时放上 X 刚好不满足条件,就说明 [i-K+1,i-1] 均为 X ,我们要减去这类方案。显然,这类方案的个数恰好就为 第 i-k 位的物品为其余两种颜色的方案数的总和。

那么根据第三种情况,可以发现当在DP状态中设置“颜色”这一维度时有利于递推。
于是设状态 dp[i][0~2] 表示第 i 个物品染色为 0~2 中的某一种时的合法方案总数。递推就根据之前的分类讨论来就行啦。

代码分享:

long long Solve(int u,int v){
	f[0][0]=1;f[0][1]=f[0][2]=0;
	for(int i=1;i<=n;++i){
		long long sum=(f[i-1][0]+f[i-1][1]+f[i-1][2])%Mod;
		f[i][2]=sum;
		if(i<=u) f[i][0]=sum;
		else if(i==u+1) f[i][0]=sum-1;
		else if(i>u+1) f[i][0]=(sum-f[i-u-1][1]-f[i-u-1][2]+Mod+Mod)%Mod;
		if(i<=v) f[i][1]=sum;
		else if(i==v+1) f[i][1]=sum-1;
		else if(i>v+1) f[i][1]=(sum-f[i-v-1][0]-f[i-v-1][2]+Mod+Mod)%Mod;
	}
	return (f[n][0]+f[n][1]+f[n][2])%Mod;
}

反思归纳:

遇到计数题目时,先对条件逐一思考,遇到刁钻的条件可以考虑转化来求解。
在转移时,通常进行分类讨论。可以先分类讨论,分析出在什么情况下自己需要那些信息来推出当前信息,并据此来设置状态转移方程。

原文地址:https://www.cnblogs.com/parauni-blog/p/13060680.html