ZJOI2010:数字计数(数位dp)

题目描述

给定两个正整数a和b,求在[a,b]中的所有整数中,每个数码(digit)各出现了多少次。

输入输出格式

输入格式:

 

输入文件中仅包含一行两个整数a、b,含义如上所述。

 

输出格式:

 

输出文件中包含一行10个整数,分别表示0-9在[a,b]中出现了多少次。

 

输入输出样例

输入样例#1: 复制

1 99

输出样例#1: 复制

9 20 20 20 20 20 20 20 20 20

说明

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

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

思路:稳妥点就用数位dp,那么记忆化搜索过程要记录什么状态呢?记录当前第几位和前面当前所求的数位之和就行了,然后注意前导0,因为前导0不算合法的位数。

# include <bits/stdc++.h>
using namespace std;
typedef long long LL;
LL dp[13][13], num[13];
int cur;
LL dfs(int pos, int lim, int zero, int sum)
{
    if(pos == -1) return sum;
    if(!zero && !lim && dp[pos][sum]+1) return dp[pos][sum];
    int up = lim?num[pos]:9;
    LL ans = 0;
    for(int i=0; i<=up; ++i) ans += dfs(pos-1, lim&&i==num[pos], zero&&i==0, sum+(cur==0&&i==0&&!zero || cur&&i==cur));
    if(!zero && !lim) dp[pos][sum] = ans;
    return ans;
}
LL solve(LL x)
{
    memset(dp, -1, sizeof(dp));
    int cnt = 0;
    while(x)
    {
        num[cnt++] = x%10;
        x /= 10;
    }
    return dfs(cnt-1, 1, 1, 0);
}
int main()
{
    LL a, b;
    scanf("%lld%lld",&a,&b);
    for(cur=0; cur<10; ++cur)
        printf("%lld ",solve(b)-solve(a-1));
    return 0;
}

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值