版权声明:本文为博主原创文章,未经博主允许不得转载。 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。
题目分析
因为题目要求输出九种数码的答案
一次性处理不是很方便,所以对每个数码
分别进行一次数位DP
表示 处理到第 位,且当前正在处理的数码已经出现了 次的数字个数
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;
}