【数位DP】洛谷P2602 [ZJOI2010]题解分析

一、题目描述

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

二、算法分析

1、文字解释

参考了OI Wiki的解释:

发现对于满 i \mathit{i} i 位的数,所有数字出现的次数都是相同的,故设数组 d p i \mathit{dp}_i dpi 为满 i 位的数中每个数字出现的次数,此时暂时不处理前导零。则有 d p i = 10 × d p i − 1 + 1 0 i − 1 \mathit{dp}_i=10 \times \mathit{dp}_{i−1}+10^{i−1} dpi=10×dpi1+10i1,这两部分前一个是来自前 i − 1 i-1 i1 位数字的贡献,后一个是来自第 i i i 位的数字的贡献。

有了 d p \mathit{dp} dp 数组,我们来考虑如何统计答案。将上界按位分开,从高到低枚举,不贴着上界时,后面可以随便取值。贴着上界时,后面就只能取 0 0 0 到上界,分两部分分别计算贡献。最后考虑下前导零,第 i i i 位为前导 0 0 0 时,此时 1 1 1 i − 1 \mathit{i-1} i1 位也都是 0 0 0,也就是多算了将 i − 1 i-1 i1 位填满的答案,需要额外减去。

重点理解 d p i \mathit{dp}_i dpi的含义

2、代码块分析(以12345外循环i=len为例,后面同理)

以下计数分为两部分:
1、最高位计数
2、非最高位计数

将12345按位存到数组

while (n) a[++len] = n % 10, n /= 10;

计算非最高位(即后4位)0-9出现次数(不包含1****)

for (int j = 0; j < 10; j++) ans[j] += dp[i - 1] * a[i];

计算最高位的所有可能数的个数,仅0****

for (int j = 0; j < a[i]; j++) ans[j] += mi[i - 1];

最高位1****出现次数另算,为12345-10000+1=2346

tmp -= mi[i - 1] * a[i], ans[a[i]] += tmp + 1;

最高位为0时(0****)位数不满,0不能作为计数,需要减去

ans[0] -= mi[i - 1];

初始准备。计算满位时非最高位次数和第高位次数(详见文字解释)

for (int i = 1; i <= 13; ++i) {
   
    dp[i] = dp[i - 1] * 10 + mi[i - 1];
    mi[i] = 10ll * mi[i - 1];
}

本文主要是为了记录解决我当初不理解的一个问题:

1、对于12345,第一层外循环i=len时仅处理了10000内的数,而剩余的2345没有处理。尽管下一循环着手处理2了,也依旧没有完全处理边界数12345,那么题目是怎么解出来的呢?
2、处理12345的2345和处理的2345这两个会有重复吗?

我草草画了一张图,接下来围绕这个图来解答上述问题。

循环次数 i 主要执行操作
5(len) 统计 [ 0 , 10000 ] \mathit[0,10000] [0,10000]内的数的0-9出现次数
4 统计 [ 0 , 2000 ] \mathit[0,2000] [0,2000]内的数的0-9出现次数
3 统计 [ 0 , 300 ] \mathit[0,300] [0,300]内的数的0-9出现次数
2 统计 [ 0 , 40 ] \mathit[0,40] [0,40]内的数的0-9出现次数
1 统计 [ 0 , 5 ] \mathit[0,5] [0,5]内的数的0-9出现次数

①解决 [ 0 , 10000 ] \mathit[0,10000] [0,10000]内的数的统计,计算了2345+1个最高位1的次数,剩余12345-10000=2345没有统计

②解决 [ 0 , 2000 ] \mathit[0,2000] [0,2000]内的数的统计,计算了345+1个最高位2的次数,剩余2345-2000=345没有统计

③解决 [ 0 , 300 ] \mathit[0,300] [0,300]内的数的统计,计算了45+1个最高位3的次数,剩余345-300=45没有统计

④解决 [ 0 , 40 ] \mathit[0,40] [0,40]内的数的统计,计算了5+1个最高位4的次数,剩余45-40=5没有统计

⑤解决 [ 0 , 5 ] \mathit[0,5] [0,5]内的数的统计,计算了1个最高位5的次数,完成统计

从上述过程中我们可以发现并不会重复计数,计数的范围越来越小,就像一串十进制数,每次循环减少一个最高位。

三、参考代码

#include <bits/stdc++.h>
using namespace std;
const int N = 15;
typedef long long ll;
ll l, r, dp[N], mi[N];
ll ans1[N], ans2[N];
int a[N];

void solve(ll n, ll *ans) {
   
  ll tmp = n;
  int len = 0;
  while (n) a[++len] = n % 10, n /= 10;
  for (int i = len; i >= 1; --i) {
   
    for (int j = 0; j < 10; j++) ans[j] += dp[i - 1] * a[i];
    for (int j = 0; j < a[i]; j++) ans[j] += mi[i - 1];
    tmp -= mi[i - 1] * a[i], ans[a[i]] += tmp + 1;
    ans[0] -= mi[i - 1];
  }
}
int main() {
   
  scanf("%lld%lld", &l, &r);
  mi[0] = 1ll;
  for (int i = 1; i <= 13; ++i) {
   
    dp[i] = dp[i - 1] * 10 + mi[i - 1];
    mi[i] = 10ll * mi[i - 1];
  }
  solve(r, ans1), solve(l - 1, ans2);
  for (int i = 0; i < 10; ++i) 
    printf("%lld ", ans1[i] - ans2[i]);
  return 0;
}

参考来源:
1、洛谷P2602 [ZJOI2010]
2、OI Wiki 数位 DP


本文入有描述不当之处还请指点一二

相关推荐

  1. P6974 [NEERC2015] Adjustment Office 题解

    2024-01-17 04:16:01       43 阅读
  2. P5469 [NOI2019] 机器人 黑题题解

    2024-01-17 04:16:01       31 阅读
  3. 题解P6995 [NEERC2014] Knockout Racing

    2024-01-17 04:16:01       13 阅读
  4. dfs专题 P1706 全排列问题——题解

    2024-01-17 04:16:01       33 阅读
  5. P1179 [NOIP2010 普及组] 数字统计

    2024-01-17 04:16:01       11 阅读
  6. P1234题解

    2024-01-17 04:16:01       12 阅读

最近更新

  1. TCP协议是安全的吗?

    2024-01-17 04:16:01       16 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2024-01-17 04:16:01       16 阅读
  3. 【Python教程】压缩PDF文件大小

    2024-01-17 04:16:01       15 阅读
  4. 通过文章id递归查询所有评论(xml)

    2024-01-17 04:16:01       18 阅读

热门阅读

  1. 1. FPGA概述

    2024-01-17 04:16:01       24 阅读
  2. 1.5 面试经典150题 - 轮转数组

    2024-01-17 04:16:01       31 阅读
  3. Spring Boot整理-Spring Boot的优势

    2024-01-17 04:16:01       25 阅读
  4. C语言中的命名规则(期末版)

    2024-01-17 04:16:01       28 阅读
  5. 什么是WiMAX技术?WiMAX宽带技术的关键技术

    2024-01-17 04:16:01       30 阅读
  6. 2024.1.13 Kafka六大机制和Structured Streaming

    2024-01-17 04:16:01       27 阅读
  7. 隐私计算的技术体系有哪些

    2024-01-17 04:16:01       28 阅读
  8. monorepo工程开发交互nodejs命令行程序

    2024-01-17 04:16:01       35 阅读
  9. Kubernetes 面试宝典

    2024-01-17 04:16:01       29 阅读
  10. HTML5笔记

    2024-01-17 04:16:01       35 阅读
  11. ubuntu卸载docker

    2024-01-17 04:16:01       31 阅读
  12. 代码随想录-刷题第五十六天

    2024-01-17 04:16:01       40 阅读
  13. 【大模型应用】小白借助chatgpt开发谷歌插件

    2024-01-17 04:16:01       30 阅读