BZOJ1833 ||洛谷P2602 [ZJOI2010]数字计数【数位DP】

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/niiick/article/details/82876352

Time Limit: 3 Sec
Memory Limit: 64 MB

Description

给定两个正整数a和b,求在[a,b]中的所有整数中,每个数码(digit)各出现了多少次。

Input

输入文件中仅包含一行两个整数a、b,含义如上所述。

Output

输出文件中包含一行10个整数,分别表示0-9在[a,b]中出现了多少次。

HINT

30%的数据中,a<=b<=10^6;
100%的数据中,a<=b<=10^12。


题目分析

因为题目要求输出九种数码的答案
一次性处理不是很方便,所以对每个数码 i i 分别进行一次数位DP

d p [ i ] [ j ] dp[i][j] 表示 处理到第 i i 位,且当前正在处理的数码已经出现了 j j 次的数字个数

lt DP(int len,int sum,int pre,int judge,int d)//judge表示上一位是否为前导0,d表示当前处理的数码
{
    if(len==0) return sum;
    if(!pre&&!judge&&dp[len][sum]!=-1) return dp[len][sum];
    lt res=0,mx=pre?dig[len]:9;
    for(int i=0;i<=mx;++i)
    {
        int add=((d!=0||(d==0&&!judge))&&i==d);//若d==0,则还要判断上一位是否为前导0,是则不能增加sum
        res+=DP(len-1,sum+add,pre&&i==mx,judge&&i==0,d);
    } 
    if(!pre&&!judge) dp[len][sum]=res;
    return res;
}
 
lt solve(lt x,int d)
{
    int len=0;
    while(x)
    {
        dig[++len]=x%10;
        x/=10;
    }
    return DP(len,0,1,1,d);
}

完整代码

#include<iostream>
#include<cstdio>
#include<vector>
#include<queue>
#include<algorithm>
#include<cstring>
using namespace std;
typedef long long lt;
 
lt read()
{
    lt f=1,x=0;
    char ss=getchar();
    while(ss<'0'||ss>'9'){if(ss=='-')f=-1;ss=getchar();}
    while(ss>='0'&&ss<='9'){x=x*10+ss-'0';ss=getchar();}
    return f*x;
}

const int maxn=20;
lt A,B;
lt dig[maxn],dp[maxn][maxn];

lt DP(int len,int sum,int pre,int judge,int d)
{
    if(len==0) return sum;
    if(!pre&&!judge&&dp[len][sum]!=-1) return dp[len][sum];
    lt res=0,mx=pre?dig[len]:9;
    for(int i=0;i<=mx;++i)
    {
        int add=((d!=0||(d==0&&!judge))&&i==d);
        res+=DP(len-1,sum+add,pre&&i==mx,judge&&i==0,d);
    } 
    if(!pre&&!judge) dp[len][sum]=res;
    return res;
}

lt solve(lt x,int d)
{
    int len=0;
    while(x)
    {
        dig[++len]=x%10;
        x/=10;
    }
    return DP(len,0,1,1,d);
}

int main()
{
    A=read();B=read();
    for(int i=0;i<=9;++i)
    {
    	memset(dp,-1,sizeof(dp));
    	printf("%lld ",solve(B,i)-solve(A-1,i));
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/niiick/article/details/82876352