当前位置: 首页 > news >正文

Acwing 数位统计DP

Acwing 338.计数问题

在这里插入图片描述
输入样例:

1 10
44 497
346 542
1199 1748
1496 1403
1004 503
1714 190
1317 854
1976 494
1001 1960
0 0

输出样例:

1 2 1 1 1 1 1 1 1 1
85 185 185 185 190 96 96 96 95 93
40 40 40 93 136 82 40 40 40 40
115 666 215 215 214 205 205 154 105 106
16 113 19 20 114 20 20 19 19 16
107 105 100 101 101 197 200 200 200 200
413 1133 503 503 503 502 502 417 402 412
196 512 186 104 87 93 97 97 142 196
398 1375 398 398 405 499 499 495 488 471
294 1256 296 296 296 296 287 286 286 247

实现思路:

  • 定义函数:count(n,x),其表示在1n中,x出现的次数(x是0-9),那么,可以用类似前缀和的思想,来求解ab中,x出现的次数:count(b,x) - count(a-1,x)

  • x = 1为例,如何计算count(n, 1):分情况讨论。比如n是个7位的数字 abcdefg我们可以分别求出1在每一位上出现的次数,然后做一个累加即可。比如求1在第4位上出现的次数,求有多少个形如xxx1yyy的数在1abcdefg之间。分两种大情况:

    • xxx = 000 ~ abc - 1, 中间d=1,yyy = 000 ~ 999,一共有abc * 1000(即左右两边数的大小相乘)种选法
    • 若xxx = abc
      • d < 1,abc1yyy > adc0efg,超出n的范围,0种
      • d = 1,yyy = 000 ~ efg,efg + 1种
      • d > 1,yyy = 000 ~ 999,1000种
  • 把上面全部的情况,累加起来,就是1出现在第四位的次数。
    类似的,可以求解出1在任意一个位置上出现的次数,累加起来,就求出了1在每一位上出现的此时,即求解出了count(n,1)

  • 注意:当x=0,不能有前导0,所以当x=0时,形如xxx0yyy,前面的xxx是从001(不能从00开始,左边选法相比不是0的情况就少了一次)999

具体实现代码(详解版):

#include <iostream>
#include <algorithm>
#include <cmath>using namespace std;//求n的位数
int get(int n){int res = 0;while(n) res ++,n /= 10;return res;
}//求1到n种i出现的次数int count(int n ,int i){int res = 0,dgt = get(n);//遍历每一位 求出每一位出现i的次数for(int j = 1 ; j <=dgt ; j ++){/*利用位运算得到当前遍历位次(第j位)的数的大小p:10^(j右边的位数即dgt-j)得到第j位左边的数大小l得到第j位右边的数大小r得到第j位上的数dj*/int p = pow(10,dgt - j), l = n / p /10,r = n % p,dj = n / p % 10;//然后分情况讨论 用i所在的位置划分出左边、右边/* 一、xxx..i..yyy的选法 左边取小于n中实际的左边的数l1)当i不为0时:左边000...~xxx...-1,右边...yyy就任意取了,取法:左边的数大小l*10^右边位数=l*p2)当i=0时,排除前导0的情况:左边000..1~xxx...-1,右边和上面一样,取法:(l-1)*p*/if(i) res += l * p;else res += (l - 1) * p;/* 二、左边固定为n的左边的数l1)、i > dj时 0种选法2)、i == dj时 yyy : 0...0 ~ r 即 r + 1 种选法3)、i < dj时 yyy : 0...0 ~ 9...9 即 10^(右边的数的位数) == p 种选法*/if(i == dj) res += r + 1;if(i < dj) res += p;}return res;
}int main(){int a,b;while(cin >> a >> b && a){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;
}

DP的难点就是分类讨论,可以具体拿个例子试一下。唉,多积累经验把~


http://www.mrgr.cn/news/44552.html

相关文章:

  • Linux的发展历史与环境
  • 【深度学习基础模型】图神经网络(Graph Neural Networks, GNNs)详细理解并附实现代码。
  • 股市突然暴涨,需要保持理性
  • 18732 最短路问题
  • Oracle 实时表空间使用率和最大表空间使用率区别
  • 自动驾驶系统研发系列—如何选择适合自动驾驶的激光雷达?从基础到高端全解读
  • STM32PWM应用
  • 智能医疗:Spring Boot医院管理系统开发
  • 【韩顺平Java笔记】第8章:面向对象编程(中级部分)【262-271】
  • win11下AMD CPU支持WSL2
  • 如何使用BlinkShot.io生成照片
  • 爬虫案例——爬取长沙房产网租房信息
  • 手势分割系统源码&数据集分享
  • MATLAB中lsqminnorm函数用法
  • 【AI知识点】批归一化(Batch Normalization)
  • ArkUI中的状态管理
  • 【编程基础知识】Java静态导入的艺术与实践
  • 【前沿 热点 顶会】NIPS/NeurIPS 2024中与尖峰/脉冲神经网络(Spiking neural networks)有关的论文
  • 大模型新人必看经验,刷到少走数月弯路!
  • 括号匹配——(栈实现)