其他分享
首页 > 其他分享> > [P2602] [ZJOI2010]数字计数(数位dp)

[P2602] [ZJOI2010]数字计数(数位dp)

作者:互联网

原题

题目描述

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

输入格式

仅包含一行两个整数 \(a,b\),含义如上所述。

输出格式

包含一行十个整数,分别表示 \(0∼9\)在 \([a,b]\)中出现了多少次。

输入输出样例

输入 #1

1 99

输出 #1

9 20 20 20 20 20 20 20 20 20

说明/提示

数据规模与约定

思路

数位dp套模板,注意前导零。

#include <algorithm>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <list>
#include <map>
#include <iostream>
#include <iomanip>
#include <queue>
#include <set>
#include <stack>
#include <string>
#include <unordered_map>
#include <vector>
#define LL long long
#define inf 0x3f3f3f3f
#define INF 0x3f3f3f3f3f3f
#define PI 3.1415926535898
#define F first
#define S second
#define endl '\n'
#define lson rt << 1
#define rson rt << 1 | 1
#define lowbit(x) (x & (-x))
#define f(x, y, z) for (int x = (y), __ = (z); x < __; ++x)
#define _rep(i, a, b) for (int i = (a); i <= (b); ++i)
#define _per(i, a, b) for (int i = (a); i >= (b); --i)
using namespace std;
LL dp[20][20];
LL l, r;
int a[20], tar;
inline LL dfs(int pos, int cnt, bool lead, bool limit)
{
    if (pos == -1)
        return cnt;
    if (!limit && !lead && dp[pos][cnt] != -1)
        return dp[pos][cnt];
    int up = limit ? a[pos] : 9;
    LL ans = 0;
    for (int i = 0; i <= up; i++)
    {
        ans += dfs(pos - 1, cnt + ((!lead || i) && (i == tar)), lead && (i == 0), limit && (i == a[pos]));
    }
    if (!limit && !lead)
        dp[pos][cnt] = ans;
    return ans;
}

inline LL solve(LL x, int num)
{
    memset(dp, -1, sizeof(dp));
    tar = num;
    int pos = 0;
    while (x)
    {
        a[pos++] = x % 10;
        x /= 10;
    }
    a[pos] = 0;
    return dfs(pos - 1, 0, true, true);
}
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cin >> l >> r;
    _rep(i, 0, 9)
    {
        cout << solve(r, i) - solve(l - 1, i) << " ";
    }
}

标签:20,int,LL,pos,ZJOI2010,P2602,include,dp,define
来源: https://www.cnblogs.com/hfcdyp/p/14136847.html