题目描述
给定两个正整数a和b,求在[a,b]中的所有整数中,每个数码(digit)各出现了多少次
一开始想歪了,想去枚举每一位,然后统计每一位的情况。
转念一想,数位dp是统计[a,b]内符合条件的数字的个数。
换一种方法,对key~[0,9],统计含1个key,2个key…len(len为数字的长度)个key的数字,然后加一下,就可以得到答案了
#include<iostream>
using namespace std;
#include<stdio.h>
#include<string.h>
long long a,b;
int g[30];
long long dp[30][30][2];
long long dfs(int key,int num,int target,int pos,bool limit,bool sta){
if(num>target) return 0;
if(pos==0){
if(key!=0){
if(num==target) return 1;
return 0;
}
else{
if(num==target&&sta) return 1;
return 0;
}
}
if(!limit&&dp[pos][num][sta]!=-1) return dp[pos][num][sta];
int up=limit?g[pos]:9;
long long res=0;
for(int i=0;i<=up;i++){
if(key==0){
if(i==0)
if(sta) res+=dfs(key,num+1,target,pos-1,limit&&i==g[pos],true);
else res+=dfs(key,0,target,pos-1,limit&&i==g[pos],false);
else
res+=dfs(key,num,target,pos-1,limit&&i==g[pos],sta||i>0);
}
else{
if(i==key)
res+=dfs(key,num+1,target,pos-1,limit&&i==g[pos],sta);
else res+=dfs(key,num,target,pos-1,limit&&i==g[pos],sta);
}
}
if(!limit) dp[pos][num][sta]=res;
return res;
}
long long solve(long long x,int key){
long long ans=0;
int pos=0;
while(x){
g[++pos]=x%10;
x/=10;
}
for(int i=1;i<=pos;i++){
memset(dp,-1,sizeof(dp));
ans=ans+i*dfs(key,0,i,pos,true,false);
}
return ans;
}
int main(){
scanf("%lld%lld",&a,&b);
for(int i=0;i<=9;i++){
if(i) printf(" ");
printf("%lld",solve(b,i)-solve(a-1,i));
}
}