AtcoderContest058E 巧妙地状压dp

https://atcoder.jp/contests/arc058/tasks/arc058_c

题意就是构造一个长度为n的序列,其中有连续3段连续区间的和分别为X,Y,Z,问你一共多少种方案,

这题参考了题解,思路特别巧妙,首先,直接求不好求,可以将问题转化为求不满足条件的个数,我们将每个数转化为01串,1转化成1,2转成10,3转成100依次类推,23序列就可以表示为10100,而5表示为10000,包含在10100中,也就是说几个数的和的01串一定包含在这几个数的01串中,如果一个序列任何位置都不包含XYZ的01串,说明不满足条件.这里用状压dp,dp[i][s]表示前i位最后x+y+z位和为s的不合法方案数,dp求得结果,再用总的方案数10^n减去所有状态下的不合法数就是最终结果,具体见代码

#include
#include
#include
#include
#include
#define ll long long
using namespace std;
ll dp[50][1<<17];
const ll mod=1e9+7;
int n,x,y,z;
int main()
{
scanf("%d%d%d%d",&n,&x,&y,&z);
memset(dp,0,sizeof(dp));
dp[0][0]=1;
ll ans=1;
int base=((1<<(z-1))|(1<<(y+z-1))|(1<<(x+y+z-1)));//xyz的01序列,包含这个就满足条件
for(int i=1;i<=n;i++)
    ans=ans*10%mod;
    int sta=(1<<(x+y+z))-1;//所有状态
    for(int i=1;i<=n;i++)
    {
        for(int s=0;s<=sta;s++)
        {if(dp[i-1][s]==0)
        continue;
            for(int k=1;k<=10;k++)//枚举下一个状态
            {
                int now=(s<

 

你可能感兴趣的:(状压dp)