欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

【数位dp】求不超过n的数中,有多少个包含2018

程序员文章站 2022-06-17 14:54:34
...

【数位dp】求不超过n的数中,有多少个包含2018

n的范围是[0,1e9];
包含2018的意思是2018是该数的子序列,比如200176855,32018,5270168是符合条件的数, 2019,40017是不符合条件的数。

Sample Input

2018

Sample Input

1

Sample Input

20182018

Sample Input

92237


解题思路

数位dp ,记忆化搜索,从高位到低位,相当于是枚举所有的位,状态包括处理到第多少位,目前希望匹配的是什么(也就是希望得到2018中的哪个数),以及该位是否有限制(能不能取[0,9])
先数位分离,a[x]表示n的第x位,
dfs(x,nex,flag); //准备处理第x位,希望匹配到nex,flag==1表示有限制
根据flag和(nex与a[x]大小比较)来分类讨论,x位能填的数字无非是nex,a[x],其他普通的数三类。


AC代码

#include <bits/stdc++.h>
#define LL long long
using namespace std;

const LL maxn=1e5+7;

char s[maxn];
int a[maxn];
int n;
int dp[11][11][2];
int mm[10];
int dfs(int x,int nex,int flag)
{
    if(dp[x][nex][flag]!=-1) return dp[x][nex][flag];
    int ans=0;
    int y=9,res=0;
    if(x>n)
    {
        if(nex==10) return 1;
        else return 0;
    }
    if(flag)
    {

        if(a[x]==nex)
        {
            ans+=dfs(x+1,mm[nex],1);
            ans+=a[x]*dfs(x+1,nex,0);
        }
        else if(a[x]<nex)
        {
            ans+=dfs(x+1,nex,1);
            ans+=a[x]*dfs(x+1,nex,0);
        }
        else if(a[x]>nex)
        {
            ans+=dfs(x+1,mm[nex],0);
            ans+=(a[x]-1)*dfs(x+1,nex,0);
            ans+=dfs(x+1,nex,1);
        }
    }
    else
    {
        if(nex==10)
        {
            ans+=10*dfs(x+1,nex,0);
        }
        else
        {
            ans+=dfs(x+1,mm[nex],0);
            ans+=9*dfs(x+1,nex,0);
        }
    }
    //printf("dp[%d][%d][%d]=%d\n",x,nex,flag,ans);
    return dp[x][nex][flag]=ans;
}
int main()
{
    int i,j,k,x,y;
    mm[2]=0;
    mm[0]=1;
    mm[1]=8;
    mm[8]=10;
    memset(dp,-1,sizeof(dp));
    scanf("%s",s+1);
    n=strlen(s+1);
    for(i=1;i<=n;i++)
    {
        a[i]=s[i]-'0';
    }
    dfs(1,2,1);
    printf("%d\n",dp[1][2][1]);
    return 0;
}