#状压dp#D 诗人小K 分析 代码

#状压dp#D 诗人小K
分析
代码


考虑题目的唯一突破口就是(x,y,z)
那么要与二进制状态挂上钩,状态应表示某一段正好为(x,y或z)
(g[s][i])表示当前位置的元素为(i),上一次状态为(s)
所能表示出的状态,这需要分类讨论一下,特别地,当能表示出(z)时,结果为(2^z)
那么通过这个预处理,dp就很好写了


代码

#include <cstdio>
#define rr register
using namespace std;
int n,x,y,z,al,dp[140001][41],g[140001][41];
signed main(){
	scanf("%d%d%d%d",&n,&x,&y,&z),
	y+=x,z+=y,al=1<<z;
	for (rr int S=1;S<=al;++S)
	for (rr int i=1;i<=10;++i){
	    g[S][i]=1;
		if (S==al) g[S][i]=al;
		else{
			for (rr int j=0;j<z;++j)
			if (((S>>j)&1)&&i+j<=z&&(j>=x||i+j<=x)&&(j>=y||i+j<=y))
			    g[S][i]|=1<<(i+j);
			if (g[S][i]>al) g[S][i]=al;
		}
	}
	dp[1][0]=1;
	for (rr int i=0;i<n;++i)
	for (rr int S=1;S<=al;++S) if (dp[S][i])
	for (rr int j=1;j<=10;++j)
	    dp[g[S][j]][i+1]=(dp[g[S][j]][i+1]+dp[S][i])%1000000007;
	return !printf("%d",dp[al][n]);
}