题目
给定[l,r]输出其中每个数位上的数字出现的次数。(下面所指的“数字”均指的是0,1,2,3,…,9)。
题解
数位DP
爽!第一道自己做出来的数位DP!!!
设f[i]表示i位数字中,一个数字出现的次数(首位可以为0);则有f[i]=f[i-1]*10+10^(i-1)的递推式。
数字0是比较特殊的,我们要单独为其设立g[i],表示首位不为0的出现次数;则有g[i]=g[i-1]+f[i-1]*9。
接下来就是分数位讨论了,注意首位是否为0,以及是否是最高位。
我有几处错误,都是因为0!(生气)
特别注意,如果0长度为len时,首位允许为0,那么0要加的方案是f[len];如果不能为0,才加g[len]。
代码
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxl=15;
int power[maxl];
int f[maxl],g[maxl];
int num[maxl];
int a[maxl],a2[maxl];
int dfs(int len,bool iszero,bool top)
{
if(len==0) return 1;
if(!iszero && !top)
{
for(int i=1;i<=9;i++) a[i]+=f[len];
if(iszero) a[0]+=g[len];else a[0]+=f[len];//debug 0的特殊之处
return power[len];//debug power[len+1]-1
}
int up=top?num[len]:9;
int cnt=0;
for(int i=0;i<=up;i++)
{
int now=dfs(len-1 , iszero&&i==0 , top&&i==up);
if(i!=0 || !iszero) a[i]+=now,cnt+=now;//debug cnt随a
}
return cnt;
}
void solve(int x)
{
int len=0;
while(x) num[++len]=x%10,x/=10;
dfs(len,1,1);
}
int main()
{
power[0]=1;for(int i=1;i<=8;i++) power[i]=power[i-1]*10;
f[1]=g[1]=1;for(int i=2;i<=8;i++) f[i]=f[i-1]*10+power[i-1],g[i]=g[i-1]+f[i-1]*9;
int l,r;
while(scanf("%d%d",&l,&r),l!=0)
{
if(l>r) swap(l,r);
solve(r);
for(int i=0;i<=9;i++) a2[i]=a[i],a[i]=0;
solve(l-1);
for(int i=0;i<9;i++) printf("%d ",a2[i]-a[i]),a[i]=0;
printf("%d\n",a2[9]-a[9]);a[9]=0;
}
return 0;
}