#状压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]);
}
posted @ 2020-10-19 22:12  lemondinosaur  阅读(85)  评论(0编辑  收藏  举报