#状压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]);
}