poj2282 The Counting Problem(数位DP)

版权声明:本文为博主原创文章,未经博主允许不得转载,除非先点了赞。 https://blog.csdn.net/A_Bright_CH/article/details/82865788

题目

给定[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;
}

猜你喜欢

转载自blog.csdn.net/A_Bright_CH/article/details/82865788