P2602 [ZJOI2010]数字计数

题目描述

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

输入格式

输入文件中仅包含一行两个整数\(a,b\),含义如上所述。

输出格式

输出文件中包含一行 \(10\) 个整数,分别表示 \(0-9\) 在 \([a,b]\) 中出现了多少次。

说明/提示

\(30\%\)的数据中,\(a<=b<=10^6\);

\(100\%\)的数据中,\(a<=b<=10^{12}\)。


Solution

此题解仅讲想法,不讲有关数位 \(dp\)的基础知识或写法,如果还没有学过数位 \(dp\) 的可以先看别的题目

看到题解里用 \(dfs\) 做的都是设的两维或以上的状态,实际上这道题只需要一维状态就够了

设目前已经填到了第 \(pos\) 位,则不管 \(num\ -\!-\ \ pos + 1\) 位上填的是什么,之后的 \(1\ -\!-\ pos\)位上的贡献是不变的(除非是已经到了 \(limit\) 的限制了,这个之后再讨论)

那么状态很明显为 \(f[pos]\)

\(eg:\)现在要填五位的数,目前状态为 \(12XXX\), \(limit\) 为 \(30000\),则后面的三位可以直接由 \(f[3]\) 转移过来,因为这属于子结构,不对前面造成影响

为什么可以这样转移?

前面所填的数(类似于 \(eg\) 中的 \(12XXX\) 的 \(12\))的贡献如何计算?

我们可以发现,对于 \(12XXX\) 中 第四位上的 \(2\) 的贡献,是 \(10^{pos - 1}\) 的。因为 \(12XXX\) 的后三位可以填 \(000\) - \(999\) 中的任意一种,则第四位的 \(2\) 就被计算了 \(10^3\) 次,即贡献就是 \(10^{pos - 1}\)。注意:这里所讨论的 \(2\) 的贡献值,仅考虑第四位上的 \(2\) ,对于后面位置上的为子结构,在之后会考虑到,而前面位置上的,在之前已经预先考虑过了,所以不会重复也不会漏情况。

现在再来讨论 \(limit\) 的限制情况。

假设将 \(eg\) 中的 \(limit\) 改为 \(12300\),则填后三位时就只能填 \(000\) - \(300\),总共是 \(12300 - 12000 + 1\) 种,于是只用在计算贡献时加这样一个判断就可以了。


Code

#include<bits/stdc++.h>
#define ll long long
#define F(i, x, y) for(int i = x; i <= y; ++ i)
using namespace std;
const int N = 15;
ll L, R;
int cnt[N];
ll f[N];
ll add(int pos)//计算lim限制时的贡献
{
ll ans = 0;
for(int i = pos - 1; i >= 1; -- i) ans = ans * 10 + cnt[i];
return ans + 1;
}
ll dp(int pos, int x, int lim, int last)
{/* pos为第几位 x为现在在算的数码
lim为是否为限制 last为上一次的值(处理前导零)*/
if(! pos) return 0;
if(! lim && f[pos] != -1 && last != 10) return f[pos];
ll ret = 0;
F(i, (last == 10 ? 1 : 0), (lim ? cnt[pos] : 9))
{
if(i == x && (i != cnt[pos] || ! lim)) ret += pow(10, pos - 1);
else if(i == x) ret += add(pos);//分情况计算贡献
ret += dp(pos - 1, x, lim && i == cnt[pos], i);
}
if(last == 10) ret += dp(pos - 1, x, 0, last);
if(! lim) f[pos] = ret;
return ret;
}
ll work(int x, ll r)
{
memset(f, -1, sizeof(f));
int num = 0;
for(r; r; r /= 10) cnt[++ num] = r % 10;
return dp(num, x, 1, 10);
}
int main()
{
cin >> L >> R;
F(i, 0, 9) printf("%lld ", work(i, R) - work(i, L - 1));
printf("\n");
return 0;
}

Thanks

如果有任何疑问欢迎提出或和我一起讨论(′▽`〃)

【题解】P2602 数字计数 - 数位dp的更多相关文章

  1. 洛谷 - P2602 - 数字计数 - 数位dp

    https://www.luogu.org/problemnew/show/P2602 第二道数位dp,因为“数位dp都是模板题”(误),所以是从第一道的基础上面改的. 核心思想就是分类讨论,分不同情 ...

  2. [bzoj1833][ZJOI2010]count 数字计数——数位dp

    题目: (传送门)[http://www.lydsy.com/JudgeOnline/problem.php?id=1833] 题解: 第一次接触数位dp,真的是恶心. 首先翻阅了很多很多一维dp,因 ...

  3. Luogu P2602 [ZJOI2010]数字计数 数位DP

    很久以前就...但是一直咕咕咕 思路:数位$DP$ 提交:1次 题解:见代码 #include<cstdio> #include<iostream> #include<c ...

  4. 洛谷P2602 [ZJOI2010]数字计数(数位dp)

    数字计数 题目传送门 解题思路 用\(dp[i][j][k]\)来表示长度为\(i\)且以\(j\)为开头的数里\(k\)出现的次数. 则转移方程式为:\(dp[i][j][k] += \sum_{t ...

  5. bzoj1833: [ZJOI2010]count 数字计数(数位DP+记忆化搜索)

    1833: [ZJOI2010]count 数字计数 题目:传送门 题解: 今天是躲不开各种恶心DP了??? %爆靖大佬啊!!! 据说是数位DP裸题...emmm学吧学吧 感觉记忆化搜索特别强: 定义 ...

  6. 【BZOJ-1833】count数字计数 数位DP

    1833: [ZJOI2010]count 数字计数 Time Limit: 3 Sec  Memory Limit: 64 MBSubmit: 2494  Solved: 1101[Submit][ ...

  7. BZOJ 1833 数字计数 数位DP

    题目链接 做的第一道数位DP题,听说是最基础的模板题,但还是花了好长时间才写出来..... 想深入了解下数位DP的请点这里 先设dp数组dp[i][j][k]表示数位是i,以j开头的数k出现的次数 有 ...

  8. UVA.1640.The Counting Problem / BZOJ.1833.[ZJOI2010]数字计数(数位DP)

    题目链接 \(Description\) 求\([l,r]\)中\(0,1,\cdots,9\)每个数字出现的次数(十进制表示). \(Solution\) 对每位分别DP.注意考虑前导0: 在最后统 ...

  9. 1833: [ZJOI2010]count 数字计数——数位dp

    传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=1833 省选之前来切一道裸的数位dp.. 题意 统计[a,b]中0~9每个数字出现的次数(不算 ...

随机推荐

  1. prometheus远程写参数优化

    一.概述 prometheus可以通过远程存储来解决自身存储的瓶颈,所以其提供了远程存储接口,并可以通过过配置文件进行配置(prometheus.yml).一般情况下我们使用其默认的配置参数,但是为了 ...

  2. Mysql性能优化:如何给字符串加索引?

    导读 现代大部分的登录系统都支持邮箱.手机号码登录两种方式,那么如何在邮箱或者手机号码这个字符串上建立索引才能保证性能最佳呢? 今天这篇文章就来探讨一下在Mysql中如何给一个字符串加索引才能达到性能 ...

  3. JAVA——桌球游戏(动画)

    跟着视频敲得 ,虽然不是自己的思路 ,不过对代码多了一点了解:涉及到继承类 主函数:创建一个BallGame对象,调用一个launchFrame函数 : launchFrame函数:严格来说是方法 , ...

  4. [POJ2533]Longest Ordered Subsequence<dp>

    题目链接:http://poj.org/problem?id=2533 描述: A numeric sequence of ai is ordered if a1 < a2 < ... & ...

  5. Java中使用RSA算法加密

    Java中使用RSA算法加密 概述 RSA加密算法是一种非对称加密算法 RSA加密的方式 使用公钥加密的数据,利用私钥进行解密 使用私钥加密的数据,利用公钥进行解密 RSA是一对密钥.分别是公钥和私钥 ...

  6. Centos7 搭建FTP服务

    安装vsftpd yum install -y vsftpd 修改配置文件 cd /etc/vsftpd user_list # 白名单 ftpusers # 黑名单 vsftpd.conf # 配置 ...

  7. SciPy - 正态性 与 KS 检验

    假设检验的基本思想 若对总体的某个假设是真实的,那么不利于或者不能支持这一假设的事件A在一次试验中是几乎不可能发生的:如果事件A真的发生了,则有理由怀疑这一假设的真实性,从而拒绝该假设: 假设检验实质 ...

  8. Github使用SSH的步骤

    1) 打开git bash命令行工具 2) 输入下面命令生成一对私钥和公钥 ssh-keygen -t rsa -b 4096 -C "你的github的邮箱" 3) 输入公钥和私 ...

  9. Hadoop安装教程_分布式

    Hadoop的分布式安装 hadoop安装伪分布式以后就可以进行启动和停止操作了. 首先需要格式化HDFS分布式文件系统.hadoop namenode -format 然后就可以启动了.start- ...

  10. Flask入门 之 没有装饰器的路由

    有些时候,需要一个类似路由的功能,但又不能或者不想写装饰器,这该怎么办? so easy! eg: @app.route('login') def login(): return 'hello wor ...