题目链接:https://loj.ac/problem/10169
题目大意
给定两个正整数 a 和 b,求在[a,b]中的所有整数中,每个数码 (digit) 各出现了多少次。
解题思路
数位dp,维护每个数字出现次数和数字个数。设当前状态为ans,子状态为tmp。状态转移如下。
注意有前导零时,不能把之前的零算进去,所以要特判一下。
AC代码
#include <iostream>
#include <stdio.h>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
struct node
{
ll s;
ll a[10];
node()
{
s=0;
for(int i=0;i<=9;++i)
a[i]=0;
}
}dp[15];
int b[15];
int cnt;
ll x,y;
void init(ll n)
{
cnt=0;
while(n)
{
b[++cnt]=n%10;
n/=10;
}
}
node dfs(int pos,int limit,int lead)
{
if(!pos)
{
node t;
t.s=1;
return t;
}
if(!limit&&!lead&&dp[pos].s)
return dp[pos];
int up=limit?b[pos]:9;
node ans;
ans.s=0;
for(int i=0;i<=9;++i)
ans.a[i]=0;
for(int i=0;i<=up;++i)
{
node tmp=dfs(pos-1,limit&&i==up,lead&&i==0);
ans.s+=tmp.s;
for(int j=0;j<=9;++j)
ans.a[j]+=tmp.a[j];
if(!lead||i!=0)
ans.a[i]+=tmp.s;
}
if(!limit&&!lead)
dp[pos]=ans;
return ans;
}
int main()
{
scanf("%lld%lld",&x,&y);
init(x-1);
node l=dfs(cnt,1,1);
init(y);
node r=dfs(cnt,1,1);
for(int i=0;i<=9;++i)
printf("%lld ",r.a[i]-l.a[i]);
puts("");
return 0;
}