题意:给定两个正整数a和b,求在[a,b]中的所有整数中,每个数码(digit)各出现了多少次。
状态:dp[i,j,k]:枚举到第j位数时,数字i出现的次数为k次的所有数字中i出现的总次数。
边界:dp[0~9,0,k]=k。
状态转移:dp[i,j-1,k+(i==第j位的数字&&不前导0)]
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
typedef long long ll;
const int inf=0x3f3f3f3f;
ll dp[10][20][20];
int digit[20];
ll dfs(int pos,int cur,int sum,bool limit,bool lead)
{
if(pos==-1) return sum;
if(!limit&&!lead&&dp[cur][pos][sum]!=-1) return dp[cur][pos][sum];
ll ret=0;
int up= limit? digit[pos]:9;
for(int i=0;i<=up;++i)
{
int p=i;
if(!i&&lead) p=-inf;
ret+=dfs(pos-1,cur,sum+(cur==p),limit&&i==digit[pos],p==-inf);
}
if(!lead&&!limit) dp[cur][pos][sum]=ret;
return ret;
}
ll solve(ll n,int i)
{
int pos=0;
while(n)
{
digit[pos++]=n%10;
n/=10;
}
return dfs(--pos,i,0,1,1);
}
int main()
{
ll a,b;
cin>>a>>b;
if(a>b) swap(a,b);
memset(dp,-1,sizeof(dp));
for(int i=0;i<=9;++i)
{
cout<<solve(b,i)-solve(a-1,i);
if(i!=9) putchar(' ');
else putchar('\n');
}
return 0;
}