ARC058 E Iroha and Haiku
开始想了一个七维dp,发现会算重
然后就去看题解了(真颓,没希望了)
显然直接做没啥希望,考虑最基本的容斥
用10^n-不包含(X,Y,Z)的方案数
考虑一个神奇的状压1用001表示,2用010表示,3用100表示。即i用(1<<(i-1))表示
在这里加法操作也有其他的定义
比如:我们"2+3”表示为10100,"3+4"表示为1001000
显然的一点考虑c=a+b+c,那么c所对应的状态一定被a+b+c所对应的状态所包含
同样的,如果c被一个集合S包含,那么S所对应的状态一定可以构成c
比如5+6肯定被2+3+6包含
所以我们用dp[i][j]表示考虑了i个数,当前状态构成的集合状态为j的方案数
转移的话枚举一下当前i选了哪个
如果构成的集合包含了X+Y+Z那么我们就不从dp[i-1][j]转移给它,否则加上去
注意我们发现这里的j最多只有17位是有用的,所以复杂度为n*10*2^17
代码如下:
#include<bits/stdc++.h> #define Mod 1000000007 using namespace std; int n,x,y,z,dp[45][1<<18]; int main(){ scanf("%d%d%d%d",&n,&x,&y,&z); int unuse=(1<<(z-1))|(1<<(z+y-1))|(1<<(x+y+z-1)); dp[0][0]=1; int tmp1=(1<<(x+y+z))-1; for (int i=1;i<=n;i++){ for (int j=0;j<=tmp1;j++){ for (int k=1;k<=10;k++){ int S=(j<<k)|(1<<(k-1)); S=S&tmp1; if ((S&unuse)!=unuse) dp[i][S]=1ll*(dp[i][S]+dp[i-1][j])%Mod; } } } int ans=1; for (int i=1;i<=n;i++) ans=1ll*ans*10%Mod; for (int i=0;i<=tmp1;i++){ if ((i&unuse)==unuse) continue; ans=ans-dp[n][i]; if (ans<0) ans+=Mod; } printf("%d\n",ans); return 0; }