动态规划篇(数位统计DP)

发布于:2025-03-30 ⋅ 阅读:(63) ⋅ 点赞:(0)

一、计数问题

 

#include <iostream>
#include <vector>

using namespace std;

int get(vector<int> num , int l , int r)
{
    int res = 0;
    for(int i = l ; i >= r ; i--)
        res = res * 10 + num[i];

    return res;
}

int power10(int x)
{
    int res = 1;
    while(x--)
        res *= 10;
    return res;
}

int count(int n , int x)
{
    if(!n) return 0;

    vector<int> num;
    while(n)
    {
        num.push_back(n % 10);
        n /= 10;
    }

    n = num.size();
    int res = 0;
    for(int i = n - 1 - !x ; i >= 0 ; i--)
    {
        if(i < n - 1)//当计算最高为时,不存在第一种情况①
        {
            res += get(num , n - 1 , i + 1) * power10(i);
            if(!x) res -= power10(i);//如果找的数是0,则不存在前导全零的情况,要减掉1种状况
        }
        if(num[i] > x) res += power10(i);
        else if(num[i] == x) res += get(num , i - 1 , 0) + 1;
    }
    return res;
}

int main()
{
    int n , m;
    while(cin >> n >> m , n || m)
    {
        if(n > m) swap(n , m);
        for(int i = 0 ; i <= 9 ; i++)
            cout << count(m , i) - count(n - 1 , i) << ' ';
        cout << endl;
    }
    return 0;
}

 

#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>
#include <cmath>

using namespace std;


vector<int> dp(int n)
{
    vector<int> res(10, 0);
    if(!n) return res;

    vector<int> nums, last(10, 0);
    while (n) 
    {
        nums.push_back(n % 10);
        n /= 10;
    }

    //先求出位数在[1,nums.size()-1]之间的数中各位数的个数
    int len = nums.size() - 1;
    for (int i = 1; i < 10; i++) res[i] = len * pow(10, len - 1);
    if(len == 1) res[0] = 0;
    else if(len == 2) res[0] = 9;
    else
    {
        string t(len, '0');
        t[0] = '9';
        t[len - 1] = '1' + len - 3;
        for (int i = 1; i < len - 1; i++) t[i] = '8';
        reverse(t.begin(), t.end());
        res[0] = atoi(t.c_str()); 
    } 

    //求出位数为nums.size()的数中各位数的个数
    for (int i = nums.size() - 1; i >= 0; i--)
    {
        int x = nums[i];

        for (int j = i == nums.size() - 1; j < x; j++)
        {
            res[j] += pow(10, i);//j出现的个数
            for (int k = 0; k < 10; k++)
            {
                res[k] += last[k] * pow(10, i);//前缀中各位数出现次数
                res[k] += pow(10, i - 1) * i;//后缀中各位数出现次数
            }
        }
        last[x]++;//累计前缀

        //原数中每个数出现的次数也要累加进去(最右叶子节点)
        if(!i)
            for (int k = 0; k < 10; k++) res[k] += last[k]; 
    }

    return res;
}
int main()
{ 
    int a, b;
    while (cin >> a >> b ,  a | b)
    {
        if(a > b) swap(a, b);
        vector<int> v1 = dp(a - 1);
        vector<int> v2 = dp(b);

        for (int i = 0; i < 10; i++)
            cout << v2[i] - v1[i] << ' ';
        cout << endl;
    }
}


网站公告

今日签到

点亮在社区的每一天
去签到