P2602 [ZJOI2010]数字计数

Posted tony-double-sky

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了P2602 [ZJOI2010]数字计数相关的知识,希望对你有一定的参考价值。

P2602 [ZJOI2010]数字计数

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

Solution

一眼识数位dp
(dp[i][j]) 对某个指定的数码, 填了 (i) 位, 其中有 (j) 位填了特定数码的 总数码数
然后分一下前导零, 最高位, 数位dp即可
看代码

Code

#include<iostream>
#include<cstdio>
#include<queue>
#include<cstring>
#include<algorithm>
#include<climits>
#define LL long long
#define REP(i, x, y) for(LL i = (x);i <= (y);i++)
using namespace std;
LL RD(){
    LL out = 0,flag = 1;char c = getchar();
    while(c < '0' || c >'9'){if(c == '-')flag = -1;c = getchar();}
    while(c >= '0' && c <= '9'){out = out * 10 + c - '0';c = getchar();}
    return flag * out;
    }
const LL maxn = 19;
LL num[maxn];
LL mem[maxn];
LL dp[maxn][maxn];//填完i位,填了j个给定数码的数码总数
LL a, b;
LL DP(LL Index, LL sum, LL state, bool zero, bool limit){
    if(Index == 0)return sum;//填完一组新的,总数累加sum
    if(!zero && !limit && dp[Index][sum] != -1)return dp[Index][sum];
    LL ans = 0, up = limit ? num[Index] : 9, add = 0;
    REP(i, 0, up){
        if(state != 0 || (state == 0 && !zero))add = (i == state);
        ans += DP(Index - 1, sum + add, state, zero && i == 0, limit && i == num[Index]);
        }
    if(!zero && !limit)dp[Index][sum] = ans;
    return ans;
    }
LL get_num(LL x, LL state){
    LL len = 0;
    while(x){
        num[++len] = x % 10;
        x /= 10;
        }
    return DP(len, 0, state, 1, 1);
    }
void init(){
    a = RD(), b = RD();
    memset(dp, -1, sizeof(dp));
    }
void solve(){
    REP(i, 0, 9){
        printf("%lld ", get_num(b, i) - get_num(a - 1, i));
        }
    puts("");
    }
int main(){
    init();
    solve();
    return 0;
    }

以上是关于P2602 [ZJOI2010]数字计数的主要内容,如果未能解决你的问题,请参考以下文章

题解P2602 [ZJOI2010]数字计数

P2602 [ZJOI2010]数字计数

P2602 [ZJOI2010]数字计数

P2602 [ZJOI2010]数字计数

P2602 [ZJOI2010]数字计数

Luogu P2602 [ZJOI2010]数字计数