【ATcode】和風いろはちゃん / Iroha and Haiku(巧妙的DP)

博客围绕一道题目展开,题目给出三个数x、y、z和N,N个位置添加数字,要求连续位置数的和能得到x、y、z,求满足题意的序列种类数并对1e9+7取模。介绍了解题思路,如用特定方式表示数,枚举并减去不符合情况,还解释了状态转移方程,最后给出代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目链接

题目大意:给出你三个数x,y,z还有N,有N个位置,位置用来添加数字,要求连续位置上的数的和能够得到x,y,z不要求所有位置都用得到,求出所有的满足题意的序列的种类数,对1e9+7取模

思路:这个题目的思路还是很清奇的,有点好玩吧,

首先,我们将1=1,2=10,3=100,5=10000,也就是要注意后面0的个数,

可以这样说,我想表示x那么就可以表示为1后面共有x-1个0,

这样能表示我要添加上的每一个数的值,计算起来也比较方便,直接从后面加上就可以了,

然后就是准备好枚举每一个数就可以了,因为前面的情况还是很多的所以我就直接减去了他不符合的情况,

还有一个很关键的点,就是包含,

比如说,我们现在的5=10000,我们可以搞成2+3=10100 4+1=10001 看上去的话,我们可以发现他们和我们需要的5都是满足包含关系的,其实说白了就是该有的几个点你肯定要有,其他的就是我们找到的情况,没错,好好想想

解释一下状态转移方程吧,

DP[i][j&S]也就表示了添加到第i个数,然后数为j&S时候不符合的情况,下面代码中有解释,可以看看。。。

代码:

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#define ll long long
using namespace std;
const int mod=1e9+7;
int dp[50][1<<17];
int fow,S,ans;
int x,y,z;
int n;
int main()
{
    scanf("%d",&n);
    scanf("%d%d%d",&x,&y,&z);
    ans=1;
    for(int i=1;i<=n;i++)
        ans=1ll*ans*10%mod;
    S=(1<<x+y+z)-1;
    fow=(1<<x-1)|(1<<x+y-1)|(1<<x+y+z-1);
    dp[0][0]=1;
    for(int i=1;i<=n;i++)
    {
        for(int j=0;j<=S;j++)//枚举我在添加第n个数时候前n-1个数的所有可能
        {
            for(int k=1;k<=10;k++)//枚举每一种可能
            {
                int T=(j<<k)|(1<<k-1);//相当于是从后面拼接上一个我需要加上的数
                T&=S;
                if ((T&fow)!=fow) dp[i][T]=(dp[i][T]+dp[i-1][j])%mod;//对不上号也就是不符合的情况,也就是上面提到的包含的情况
            }
        }
    }
    for(int i=0;i<=S;i++)
        ans=(ans-dp[n][i]+mod)%mod;
    printf("%d\n",ans);
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值