数位dp的简单使用

题目:给出不多1000位的数,每一位由0、1、2、3组成。
条件:所有的0都在1之前,所有的2都在3之前,0不能在首位,另外0、1、2、3必须出现至少一次。由于数较大所以结果对1000000007取余。
问题:求满足条件的数的数量。

分析:明显这类题目是无法通过暴力遍历解决的。所以需要通过数位dp解决。

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int dp[1005][2][2][2][2],digit[1005];
void init()
{
    memset(dp,-1,sizeof(dp));   //初始化dp数组
}
int dfs(int len,int i,int j,int k,int l,int flag)   //len表示当前位,i,j,k,l分别表示是否包含0、1、2、3(0表示不包含,1表示包含),flag表示是否达到上限(1为达到,0为未达到)
{
    if(len<=0)
        return (i&&j&&k&&l);
    if(!flag&&dp[len][i][j][k][l]!=-1)
        return dp[len][i][j][k][l];
    int n=flag?digit[len]:3;
    int ans=0;
    for(int i1=0;i1<=n;i1++)
    {
        int i2=i,j1=j,k1=k,l1=l;
        if(j==0&&k==0&&l==0&&i1==0)
            continue;
        if(i1==0&&j==1)
            continue;
        else if(i1==0&&j==0)
            i2=1;
        else if(i1==1&&i==0)
            continue;
        else if(i==1&&i1==1)
            j1=1;
        else if(i1==2&&l==1)
            continue;
        else if(i1==2&&l==0)
            k1=1;
        else if(i1==3&&k==0)
            continue;
        else if(i1==3&&k==1)
            l1=1;
        ans=(ans+dfs(len-1,i2,j1,k1,l1,flag&&i1==n))%1000000007;
    }
    if(!flag)
        dp[len][i][j][k][l]=ans;
    return ans;
}
int main()
{
    int n,summ;
    scanf("%d",&n);
    init();
    digit[n]=2;
    for(int i=n-1;i>0;i--)
        digit[i]=3;
    summ=dfs(n,0,0,0,0,1);
    printf("%d\n",summ);
    return 0;
}
另外,数位dp上面这种实现方式必须dfs函数的for循环对于i,j,k,l形参的操作必须重新定义变量,而不能直接使用原变量,因为这可能导致for循环的下一个循环的变量i,j,k,l改变。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值