Acwing 数位统计DP

news/2024/10/7 15:07:56/

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.ppmy.cn/news/1535746.html

相关文章

系统设计,如何设计一个秒杀功能

需要解决的问题 瞬时流量的承接防止超卖预防黑产避免对正常服务的影响兜底方法 前端设计 利用 CDN 缓存静态资源&#xff0c;减轻服务器的压力在前端随机限流按钮防抖&#xff0c;防止用户重复点击 后端设计 Nginx 做统一接入&#xff0c;进行负载均衡与限流用 sentinel 等…

Android15车载音频之Virtualbox中QACT实时调试(八十八)

简介: CSDN博客专家、《Android系统多媒体进阶实战》一书作者 新书发布:《Android系统多媒体进阶实战》🚀 优质专栏: Audio工程师进阶系列【原创干货持续更新中……】🚀 优质专栏: 多媒体系统工程师系列【原创干货持续更新中……】🚀 优质视频课程:AAOS车载系统+…

设计模式之装饰器模式(Decorator)

一、装饰器模式介绍 装饰模式(decorator pattern) 的原始定义是&#xff1a;动态的给一个对象添加一些额外的职责。 就扩展功能而言&#xff0c;装饰器模式提供了一种比使用子类更加灵活的替代方案。 在软件设计中&#xff0c;装饰器模式是一种用于替代继承的技术&#xff0c;它…

【信息系统项目管理师考题预测】合同管理

信息系统项目合同管理是项目管理中的重要环节,其常考题目通常涉及合同管理的各个方面,包括合同的订立、履行、变更、终止以及违约索赔管理等。 一、选择题 以下哪项不属于合同管理的范畴? A. 合同的订立 B. 回答潜在卖方的问题 C. 合同的履行 D. 合同的变更 解析:B。回答潜…

C++ list 容器类的模拟实现

前言&#xff1a; 我们不仅仅要熟悉使用c标准库中的 list 容器&#xff0c;我们更要学习了解标准库是如何将 list 容器实现出来的&#xff0c;这就是我们常说的知其然也要知其所以然&#xff0c;学习源码中优秀的部分&#xff0c;将 list 容器进行模拟实现出来&#xff0c;使得…

C++ 泛型编程指南 类模板,类型推断,特化,别名模板

文章目录 [TOC]1.声明一个类模板2.模板类成员函数实现3. 使用 Stack 类模板 4.部分使用类模板5.模板类的特例化6. 模板类的偏特化6.1 区分偏特化和全特化6.1.1 偏特化6.1.2 全特化 6.2 偏特化 例子6.2.1 指针类型偏特化6.2.2 多个参数的偏特化 解释&#xff1a;6.3 偏特化匹配歧…

解决CentOS 7 yum install 出现 No such file or directory 错误的方案

CentOS 7 yum install之后 出现No such file or directory错误的解决方案&#xff1a; [rootcentos7 ~]# yum install -y git File "/usr/bin/yum", line 30 except KeyboardInterrupt, e: ^ SyntaxError: invalid syntax [rootcentos7 ~]# yum -bash: /usr/bin/yum:…

Atcoder Beginner Contest 374 D题题解

一. 题目描述 题目传送门 - Atcoder Beginner Contest 374 D - Laser Marking 二. 思路分析 1.题目大意 在平面上给你一个激光&#xff08;可看作一个点&#xff09;和若干条线段&#xff08;左右端点分别为 ( a i , b i ) (a_i,b_i) (ai​,bi​) &#xff0c; ( c i , d…