文章目录
——2020年11月22日(周日)——————————————————
数位DP
一、计数问题
题目链接
第一次做真的很难,总之十分耗费时间。
第一次批注得这么满……
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
const int N = 10;
//get前面前缀部分的数值,即前面前缀总方案数
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;
}
//这是1到n中i出现的次数
int count(int n, int x){
//0的话就不要讨论了
if (!n) return 0;
//将n的每一位都拆下来
vector<int> num;
while (n){
num.push_back(n % 10);
n /= 10;
}
n = num.size();
//接下来是统计在当前位置上取某个数会有多少种方案
int res = 0;
/*
首先要明白,x是指在这一位取x,然后去求总共的方案数
x等于0的时候要另行讨论!
i从最高位开始枚举,枚举的是第i位出现了x的次数
*/
/*
这里假设这个序列式abcdefg,现在i在中间位置d,其前缀是abc, 后缀是efg
一、这是第i位的前缀 小于 abc 的情况(当然,首先这个位置得有前缀才可以)
000~abc - 1, 999种(也可以说是 10的i-1的次方 - 1 种);
二、这是前缀等于abc的情况,记住!前提是前缀相等!
这里分别讨论第i位的三种情况,因为这三种情况对应了不同的三种后缀的情况!
1. 第i位 大于 目标最大值的第i位,那么后缀根本取不了,也就是0种情况。
2. 第i位 等于 目标最大的第i位
此时后缀可以随便取,于是有0~efg这些情况
num[i] == x, 0~efg
3. 第i位 小于 目标最大的第i位
此时后面的位置可以随便取,有1000种情况
num[i] > x, 0~999(也就是0 ~ 10的i-1的次方 - 1 种 情况)
*/
for (int i = n - 1 - !x; i >= 0; i -- ){
//如果i所在的不是最高位,那么就会有前缀,那么我们就来先处理前缀小于abc的情况
if (i < n - 1){
//res += 前缀的值 * 10的后缀的次方
//这里前缀的情况应该是0~前缀(abc)-1,一共abc种情况,并没有把abc这种情况也算进去
res += get(num, n - 1, i + 1) * power10(i);
//如果x是0的话,前缀里面会少一种情况(就是这个情况:0...0,因为想要这一位取0,那么前缀不可能全是0);
//比如三位数里想要第二位取0,那么就可以有102,103,106……但是绝对不会有002,003,006……等情况存在,不是吗?
if (!x) res -= power10(i);
}
//然后我们来处理前缀就是abc的情况,当然啦,这里就不管有没有前缀了,都一样的~
//当前要取的数x 与 目标最大值的这一位数相等的时候 ,就是后面构成的数再加1(0这种情况)
if (num[i] == x) res += get(num, i - 1, 0) + 1;
//当前要取的数x 小于 目标最大值的这一位数 的时候,只要加上十的后面的数的位数的次方
else if (num[i] > x) res += power10(i);
}
return res;
}
int main()
{
int a, b;
while (cin >> a >> b , a){
//保证a小于b
if (a > b) swap(a, b);
//分位置来讨论 每一位上 取 某一个数 会有多少种情况
for (int i = 0; i <= 9; i ++ )
cout << count(b, i) - count(a - 1, i) << ' ';
cout << endl;
}
return 0;
}
明天大概会搞定蒙德里安那道题吧……
——2020年11月23日(周一)——————————————————
——2020年11月24日(周二)——————————————————
——2020年11月25日(周三)——————————————————
——2020年11月26日(周四)——————————————————
——2020年11月27日(周五)——————————————————
——2020年11月28日(周六)——————————————————
# ——(完)——————————————————