P1980 [NOIP2013 普及组] 计数问题
题目链接:https://www.luogu.com.cn/problem/P1980
术语
以下的英文术语均可以翻译为数字。
digit
: 一个数字字符,十进制就是 0-9 之间的一个字符;numeral
: 用来表示数字的符号化表示,如 “Three”、“3”、“III”;number
: 一种抽象的数字概念。
为了区分,下文中均使用英文术语。
注意:关于 numeral 和 number 区别见: 如何在英文写作中正确的表达数字?
十进制数表示法
十进制数(decimal numeral
)由一串有限长度的 digit
序列组成,
\]
其中,\(a_i \in \{0,1,2,3,4,5,6,7,8,9\}\)。
numeral
\(a_ma_{m-1}\ldots a_0\) 表示了 number
\(a_m10^m+a_{m-1}10^{m-1}+\cdots+a_{0}10^0\)。
注意:关于十进制数的详细介绍见 Wikipedia Decimal
前置 \(0\)
为简化问题,我们假设我们的 numeral
可以出现前置 \(0\),即,从最左侧开始,可以出现多个连续的 \(0\),如 \(03\),\(003\)。通过前置 \(0\), 我们可以使用三个 digit
来包含一位数、二位数、三位数的 number
。
三个 digit
为简化问题,我们目前只考虑三位数之内的 number
,且忽略 \(n\)(目前可视作 \(n = 999\),用来包含所有的一位数、二位数、三位数)。
出现次数是?
根据题目,我们需要统计出 digit
\(x\) 在所有 numeral
的 digit
中出现的次数。这里我们列出部分的 numeral
,
{c|c|c}
a_2&a_1&a_0\\
\hline
0&0&0\\
0&0&1\\
0&0&2\\
0&0&3\\
\vdots&\vdots&\vdots\\
9&9&6\\
9&9&7\\
9&9&8\\
9&9&9\\
\end{array}
\]
令 \(C_i\) 等于第 \(i\) 位上 \(x\) 出现的总次数,那么\(x\) 在所有 numeral
的 digit
中出现的次数为 \(S=\sum_{i=0}^2C_i\)。
\(C_i\) 等于?
我们通过 \(x = 1\) 来进行说明。首先我们令 \(a_2 = 1\),此时百位上的数字已经固定,\(a_1\) 和 \(a_0\) 分别有 \(0\) 到 \(9\) 十种可能,且彼此互不影响,所以 \(C_2 = 10 \times 10 = 100\),同理我们得到 \(C_0=C_1=100\)。从而,我们最终得到 \(S=100+100+100=300\)。
通过上面的方式,我们可以得到任意 \(x\) 对应的 \(S\)。
注意:
digit
\(0\) 比较特殊,我们这里暂时未考虑。
考虑 \(n\) 呢?
上面的问题只看 digit
的个数,但忽略了 \(n\)。如果我们也要将 \(n\) 考虑在内呢?
\(n=123\), \(x=3\)
这里以 \(n=123\),\(x=3\) 进行举例。首先我们可以知道 \(a_2 = 3\) 是不可能的,所以此时 \(C_2 = 0\)。下面我们考虑 \(a_1 = 3\),此时 \(a_2\) 必须小于 \(1\), 所以只有 \(a_2 = 0\) 一种可能,由于向前面借了一位, \(a_0\) 可以包含 \(0\) 到 \(9\) 十种可能,从而我们得到 \(C_1 = 10\)。然后我们考虑 \(a_0 = 3\),当 \(a_2 = 1\) 时,需满足 \(a_1 \leqslant 2\);当 \(a_2 = 0\) 时,\(a_1\) 可以包含 \(0\) 到 \(9\) 十种可能,加起来我们有 \(C_0 = 3 + 10 = 13\) 种可能。最终,我们得到 \(S=0+10+13=23\)。
\(n=123\), \(x=2\)
这里以 \(n=123\),\(x=2\) 进行举例。首先我们可以知道 \(a_2 = 2\) 是不可能的,所以此时 \(C_2 = 0\)。下面我们考虑 \(a_1 = 2\),此时 \(a_2\) 有 \(0\) 和 \(1\) 两种可能,当 \(a_2 = 1\), 需满足 \(a_1 \leqslant 3\);当 \(a_2 = 0\), \(a_1\) 可以包含 \(0\) 到 \(9\) 十种可能,从而我们得到 \(C_1 = 4 + 10 = 14\)。然后我们考虑 \(a_0 = 2\),当 \(a_2 = 1\) 时,需满足 \(a_1 \leqslant 2\);当 \(a_2 = 0\) 时,\(a_1\) 可以包含 \(0\) 到 \(9\) 十种可能,加起来我们有 \(C_0 = 3 + 10 = 13\) 种可能。最终,我们得到 \(S=0+14+13=27\)。
\(n=123\), \(x=1\)
这里以 \(n=123\),\(x=1\) 进行举例。首先我们令 \(a_2=1\),当 \(a_1=2\) 时,需满足 \(a_0 \leqslant 3\);当 \(a_1 \leqslant 1\) 时,\(a_0\) 可以包含 \(0\) 到 \(9\) 十种可能,故 \(C_2 = 4 + 10 + 10 = 24\)。下面我们考虑 \(a_1 = 1\),此时 \(a_2\) 有 \(0\) 和 \(1\) 两种可能,当 \(a_2 \leqslant 1\), \(a_0\) 可以包含 \(0\) 到 \(9\) 十种可能,从而我们得到 \(C_1 = 10 + 10 = 20\)。然后我们考虑 \(a_0 = 1\),当 \(a_2 = 1\) 时,需满足 \(a_1 \leqslant 2\);当 \(a_2 = 0\) 时,\(a_1\) 可以包含 \(0\) 到 \(9\) 十种可能,加起来我们有 \(C_0 = 3 + 10 = 13\) 种可能。最终,我们得到 \(S=24+20+13=57\)。
我们发现上面的统计方式,通过程序来处理的话比较麻烦,最好一种统一的方式来处理各种情况,
移除 digit
\(x\),再看看!
\(x > a_i\),
当 \(x > a_i\),我们令 \(a_{i-1} \gets a_{i-1} - 1\),\(a_k \gets 9 \text{ for } k > i\)。比如对于 \(n = 123\), \(x=3\),\(i = 2\),我们得到 \(039\),我们移除 \(a_2\) 得到 \(09\),在对 \(09 + 1\) 得到 \(10\),我们发现这正好等于 \(C_2\);\(x = a_i\),
当 \(x = a_i\),不进行额外操作。比如对于 \(n = 123\), \(x=2\),\(i = 2\),我们得到 \(123\),我们移除 \(a_2\) 得到 \(13\),在对 \(13 + 1\) 得到 \(14\),我们发现这也正好等于 \(C_2\);\(x < a_i\),
当 \(x = a_i\),我们令 \(a_k \gets 9 \text{ for } k > i\)。比如对于 \(n = 123\), \(x=1\),\(i = 2\),我们得到 \(119\),我们移除 \(a_2\) 得到 \(19\),在对 \(19 + 1\) 得到 \(20\),我们发现这又正好等于 \(C_2\)。
上面的方法可以总结为,
- 首先判断 \(x\) 和 \(a_i\) 的大小关系;
- 根据判断结果来对其他的
digit
进行修改; - 移除 \(x\) 对应的 \(a_i\),得到一个新的
numeral
- 计算
numeral
对应的number
- 最后在对得到的结果 \(+1\) 即可。
注意:如果 \(a_i\) 最高位,且 \(x > a_i\),那么此时没有可以借位的
digit
,所以 \(C_i = 0\)。
注意:
digit
\(0\) 比较特殊,我们这里暂时未考虑。
多出来 \(0\)?
如果我们按照前面的方法对 \(x = 0\) 进行统计,我们会发现 \(0\) 的次数被多统计了一些。
为了解释这个问题,这里我们再次以三个 digit
的 numeral
进行说明。
对于任意一个三位数的 \(n\),我们之前的方法会把所有有一个前置 \(0\) 和有两个前置 \(0\) 的 numeral
包含进来,比如 \(010\),\(001\)。而这些前置 \(0\) 实际上不应该被统计进来,为了得到正确的答案,我们可以在最终结果的地方减去多统计的前置 \(0\) 。
前置 \(0\) 的个数
前置 \(0\) 的个数为 \(a_2 = 0\) 的 numeral
个数,以及 \(a_2=0\) 同时 \(a_1 = 0\) 的numeral
个数,因为题目中 number
不包含 \(0\),所以我们最终还要加上 \(a_2=0\) 同时 \(a_1 = 0\) 同时 \(a_0 = 0\) 的情况。最终我们可以得到多统计的前置 \(0\) 个数为 \(100 + 10 + 1 = 10^2 + 10^1 + 10^0 = 111\)。
由此我们可以推广 \(m\) 个 digit
的 numeral
多统计的前置 \(0\) 为 \(\sum_{i=0}^{m-1} 10^i\)。
结论
- \(x \ne 0\) 时,采用移除
digit
\(x\) 的方法即可。 - \(x = 0\) 时,采用移除
digit
\(x\) 方法的同时还需要减去多余的前置 \(0\)。
代码如下:
// https://www.luogu.com.cn/problem/P1980
// https://www.cnblogs.com/revc/p/17087297.html
#include <iostream>
#include <cmath>
int main()
{
int n, x;
std::cin >> n >> x;
int digits[7];
int m = 0; // the number of digits
while(n > 0) // NOTE: store digits in reverse order
{
digits[m++] = n % 10;
n /= 10;
}
int S = 0;
for (int i = 0; i < m; i++)
{
int C = 0;
int borrow = 0;
if (x > digits[i])
{
if (i+1 == m) continue; /* fail to borrow */
borrow = 1;
digits[i+1]--;
}
for (int j = m - 1; j > i; j--)
{
C = C * 10 + digits[j];
}
for (int j = i - 1; j >= 0; j--)
{
C = C * 10 + (digits[i]==x ? digits[j] : 9);
}
digits[i+1] += borrow;
S += C + 1;
}
if (x == 0)
{
int subtrahend = 1;
while(m--)
{
S -= subtrahend;
subtrahend *= 10;
}
}
std::cout << S << std::endl;
return 0;
}
P1980 [NOIP2013 普及组] 计数问题的更多相关文章
- 洛谷——P1980 [NOIP2013 普及组] 计数问题
题目描述 试计算在区间 11 到 nn的所有整数中,数字x(0 ≤ x ≤ 9)x(0≤x≤9)共出现了多少次?例如,在 11到1111中,即在 1,2,3,4,5,6,7,8,9,10,111,2, ...
- [NOIP2013] 普及组
计数问题 纯模拟 #include<cstdio> #include<iostream> using namespace std; int main(){ int n,x; c ...
- NOIP2013普及组 -SilverN
T1 计数问题 题目描述 试计算在区间 1 到 n 的所有整数中,数字 x(0 ≤ x ≤ 9)共出现了多少次?例如,在 1 到 11 中,即在 1.2.3.4.5.6.7.8.9.10.11 中, ...
- NOIP2013普及组 T2 表达式求值
OJ地址:洛谷P1981 CODEVS 3292 正常写法是用栈 #include<iostream> #include<algorithm> #include<cmat ...
- 【NOIP2013 普及组】车站分级
[NOIP2013 普及组]车站分级 一.题目 [NOIP2013 普及组]车站分级 时间限制: 1 Sec 内存限制: 128 MB 提交: 3 解决: 0 [提交][状态][讨论版] 题目描述 ...
- [NOIP2013 普及组] 表达式求值
[NOIP2013 普及组] 表达式求值 给定一个只包含加法和乘法的算术表达式,请你编程计算表达式的值. Input 一行,为需要你计算的表达式,表达式中只包含数字.加法运算符"+" ...
- [NOIp2013普及组]车站分级
思路: 对于每一趟车,将区间内所有经停的站和所有未经停的站连一条边,表示前者优先级一定高于后者,然后用Kahn跑一遍拓扑排序即可.然而这样会创造大量多余的边,会TLE1个点.考虑一种优化:因为每趟车本 ...
- Noip2013(普及组) 车站分级
题目描述 一条单向的铁路线上,依次有编号为 , , …, n 的 n 个火车站.每个火车站都有一个级别,最低为 级.现有若干趟车次在这条线路上行驶,每一趟都满足如下要求:如果这趟车次停靠了火车站 x, ...
- NOIP2002-2017普及组题解
虽然普及组一般都是暴力省一,但是有一些题目还是挺难的qwq个人觉得能进TG的题目会在前面打上'*' NOIP2002(clear) #include<bits/stdc++.h> usin ...
- NOIP2012 普及组 T3 摆花——S.B.S.
题目描述 小明的花店新开张,为了吸引顾客,他想在花店的门口摆上一排花,共m盆.通过调查顾客的喜好,小明列出了顾客最喜欢的n种花,从1到n标号.为了在门口展出更多种花,规定第i种花不能超过ai盆,摆花时 ...
随机推荐
- Caused by: java.lang.NoClassDefFoundError: net/minidev/asm/FieldFilter 报错的解决
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'r ...
- [ABC284F] ABCBAC(字符串哈希)
思路 这里我们要注意以下几点: 字符串哈希自然溢出(\(\pmod 2^64\))会被卡,会\(WA~5\)个点 注意有模数的时候不要用\(unsigned\ long \ long\)类型 代码 # ...
- linux 修改文件内容命令
1.进入文件:vim 文件名 eg #vim /etc/httpd/httpd.conf 2.查找待修改内容位置 : (1)shift+":",使文件变成可查询状态 (2)输入 / ...
- 数据库中1NF,2NF,3NF的判别
参照:https://blog.csdn.net/qq_28888837/article/details/98733448 1NF:每一个都是最原子化. 2NF:找到主键后,每一个非主键对主键都是完 ...
- wx.BoxSizer布局管理器用法,及其Add()方法参数说明
wx.BoxSizer 布局管理器是一种常见的布局管理器,它可以在水平或垂直方向上布置子窗口部件.同时,它还可以在水平或垂直方向上包含其他 wx.BoxSizer 来创建复杂的布局. 下面是 wx.B ...
- 这样封装echarts简单好用
为什么要去封装echarts? 在我们的项目中,有很多的地方都使用了echarts图表展示数据. 在有些场景,一个页面有十多个的echarts图. 这些echarts只是展示的指标不一样. 如果我们每 ...
- Centos7端口开放及查看
1.开放端口 firewall-cmd --zone=public --add-port=端口/tcp --permanent eg:firewall-cmd --zone=public --add- ...
- AIGC时代:未来已来
摘要:人工智能的快速发展使得我们进入了AIGC时代.AIGC时代的到来,将会带来巨大的机遇和挑战. 本文分享自华为云社区<GPT-4发布,AIGC时代的多模态还能走多远?系列之一: AIGC时代 ...
- 二进制安装Kubernetes(k8s) v1.23.6
二进制安装Kubernetes(k8s) v1.23.6 背景 kubernetes二进制安装 1.23.3 和 1.23.4 和 1.23.5 和 1.23.6 文档以及安装包已生成. 后续尽可能第 ...
- 【CTF】日志 2019.7.13 pwn 堆溢出基础知识
十六进制两位表示一个字节 堆溢出 先上堆图: 堆的数据结构 一般情况下,物理相邻的两个空闲 chunk 会被合并为一个 chunk struct malloc_chunk { INTERNAL_SIZ ...