BZOJ 1833 count 数字计数 (数位DP)

给定两个正整数a和b,求在[a,b]中的所有整数中,每个数码(digit)各出现了多少次。
Input
输入文件中仅包含一行两个整数a、b,含义如上所述。
Output
输出文件中包含一行10个整数,分别表示0-9在[a,b]中出现了多少次。
Sample Input
1 99
Sample Output
9 20 20 20 20 20 20 20 20 20
Hint

30%的数据中,a<=b<=10^6;
100%的数据中,a<=b<=10^12。


Emmmmm…………

说实话这个题我是怎么过的我都不知道………………

一共十个数字0,1,2,3,4,5,6,7,8,9,不可能一下子全部算出来,还是先算0再算1这样子遍历每一个数字分开计算

dp[ i ] 表示第 i 位为止的数后面出现了多少个 0 ( or 1,2 ..........9  )

然后就瞎搞

其实这个题对于每一个数码找它出现的次数的思路应该还是蛮清晰的吧。。。。。。


代码:

#include <iostream>
#include <stdio.h>
#include <math.h>
#include <string.h>
#include <vector>
#include <algorithm>
#include <map>
using namespace std;
typedef long long LL;
#define fi first
#define se second
LL dp[20],s[20],t[20];
LL n[20];
LL a,b,m;
LL dfs(LL pos,LL sum,LL num,bool limit)
{
    if(pos==-1)
    {
        if(sum==0&&num==0&&m==0)return 1;
        else return 0;
    }
    if(!limit&&sum>0&&dp[pos]>-1)return dp[pos];
    LL up=limit?n[pos]:9;
    LL res=0;
    for(int i=0;i<=up;i++)
    {
        LL z=(sum*10+i>0)&&(i==m);
        if(limit&&i==up)
        {
            res+=z*(pos>0?(s[pos-1]+1):1)+dfs(pos-1,sum*10+i,i,true);
        }
        else
        {
            res+=z*t[pos]+dfs(pos-1,sum*10+i,i,false);
        }
    }
     if(!limit&&sum>0)dp[pos]=res;
     return res;
}

LL solve(LL x)
{
    LL len=0;
    while(x)n[len++]=x%10,x/=10;
    s[0]=n[0];t[0]=1;
    LL z=10;
    for(int i=1;i<len;i++)s[i]=s[i-1]+n[i]*z,t[i]=z,z*=10;
    //for(int i=0;i<len;i++)cout<<s[i]<<' ';puts("");
    return dfs(len-1,0,0,true);
}


int main()
{
    while(scanf("%lld%lld",&a,&b)!=-1)
    {
        a--;
        for(m=0;m<=9;m++)
        {
            memset(dp,-1,sizeof(dp));
            printf("%lld",solve(b)-solve(a));
            if(m<9)putchar(' ');else putchar('\n');
        }
    }
    return 0;
}

大概就是这样了。。。。。

本人蒟蒻,如有错误,还望指正


(虽然今天是8月4号晚了一天的但还是要说果果生日快乐)


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值