数位dp——统计'1'的个数
今天去牛客网看了看 包含一 这道题,一开始没看清,以为它要统计 1~n 所有数中数字 '1' 出现的总次数,也就是说,若 n == 11,则 ans = 4;而按照题目的原意 ans 应该为 3。看错题意后还是挣扎了好久,具体的调试过程也不想回忆叙述了,先贴上按照我一开始理解的意思的代码吧,虽然没有题目让我测,但我和自己写的暴力法对拍过,应该没问题的。
#include<cstdio>
#include<cstring>
#include<vector>
#include<algorithm>
using namespace std;
typedef long long LL; LL C[][], p9[] = {,};
// C 数组为组合数,p9 是 9 的幂数组
inline void initC(const int &n = ) {
for(int i = ; i <= n; ++i)
C[i][] = ;
for(int i = ; i <= n; ++i)
for(int j = ; j <= n; ++j)
C[i][j] = C[i-][j-] + C[i-][j];
for(int i = ; i <= n; ++i)
p9[i] = p9[i-] * ;
} LL all[], num0[], num1[];
// all[i] 表示 i 位数的个数,num0[i] 表示不含数字 1 的 i 位数的个数
// num1[i] 表示 i 位数中含有数字 1 出现的总次数,注意是 '1' 出现的总次数!求法有点麻烦
inline void init(const int &k = ) {
all[] = ;
num0[] = ;
for(int i = ; i <= k; ++i) {
all[i] = all[i-] * ;
num0[i] = num0[i-] * ;
}
initC();
for(int n = ; n <= k; ++n) {
LL &sum = num1[n];
sum = ;
for(int i = ; i <= n; ++i)
sum += i * C[n][i] * p9[n-i];
}
} // 和数位 dp 的分析步骤有点类似
inline LL solve(const LL &n) {
LL digit[], len = , x = n;
while(x) {
digit[++len] = x % ;
x /= ;
}
int count = ; // 统计前 i 位数字 1 的个数
LL sum = ;
// 核心计数部分(结合曾经做过的数位 dp 的思路来考虑)
for(LL i = len; i > ; --i) {
sum += digit[i] * num1[i-]; // 先加上当第 i 位取 0~digit[i]-1 时,i-1 位数的数字 1 的总个数
if(count) sum += count * digit[i] * all[i-]; // 统计前面的 1 的个数(第 i 位后取任何数字都没所谓)
if(digit[i] == ) ++count; // 计数器加 1
if(digit[i] > ) sum += all[i-]; // 统计若当前位取 1 时的个数(同理后面是什么都没所谓)
}
// 好好体会下这个数位 dp 的思路,要做到不重不漏真不容易~
return sum;
} // 分解统计 '1' 的个数
inline LL caclu(LL x) {
LL res = ;
while(x) {
if(x % == ) ++res;
x /= ;
}
return res;
} // 暴力枚举统计
inline LL test(const LL &x) {
LL sum = ;
for(LL i = ; i <= x; ++i)
sum += caclu(i);
return sum;
} int main() {
LL n;
init();
while(~scanf("%I64d",&n))
printf("solve = %I64d test = %I64d\n\n",solve(n+),test(n));
return ;
}
统计 1~n 中数字'1'出现的总次数
后来,按照题目的意思我又重做了一遍:
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std; int dp[][];
// dp[0][i] 表示包含 1 的 i 位数的个数
// dp[1][i] 表示以 1 开头的不包含 1 的 i 位数的个数
// dp[2][i] 表示不包含 1 的 i 位数的个数
// 其实 dp[1][i] 和 dp[2][i] 实质是一样的,合并成一个就行了,所以空间和时间都能提升一点;为了让它更直观,我就不改了
inline void init(int n = ) {
dp[][] = ;
for(int i = ; i <= n; ++i) {
dp[][i] = * dp[][i-] + dp[][i-];
dp[][i] = dp[][i-];
dp[][i] = dp[][i-] * ;
}
} inline int solve(int x) {
int digit[], len = ;
while(x) {
digit[++len] = x % ;
x /= ;
}
bool flag = ;
int sum = ;
for(int i = len; i; --i) {
sum += digit[i] * dp[][i-];
if(flag) sum += digit[i] * dp[][i-];
else if(digit[i] > ) sum += dp[][i];
if(digit[i] == ) flag = ;
}
return sum;
} const int inf = 0x7fffffff; int main() {
int n;
init();
while(~scanf("%d",&n)) { // 有符号 int 的上限,要注意处理好
if(n == inf) printf("%d\n",solve(n) + );
else printf("%d\n",solve(n+));
}
return ;
}
统计包含'1'的数字的个数
耗费了一个中午和下午时间写完这两个代码后,我发觉我对于数位 dp 已经感到无爱了,再给我来一道这样的题的话就真的要挂了~
---------------------------------------------来填一下坑先---------------------------------------------------
后来发现,原来还有这样的一道题 统计一,把我第一个代码的 I64d 改为 lld 以及输出修改一下就能过,果然我的做法是对哦~
数位dp——统计'1'的个数的更多相关文章
- ACM学习历程—HDU5587 Array(数学 && 二分 && 记忆化 || 数位DP)(BestCoder Round #64 (div.2) 1003)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5587 题目大意就是初始有一个1,然后每次操作都是先在序列后面添加一个0,然后把原序列添加到0后面,然后 ...
- 2019牛客多校第六场H Pair(数位DP 多个数相关)题解
题意: 传送门 给你\(A,B,C\),要求你给出有多少对\((x, y)\)满足\(x\in [1,A],y\in [1,B]\),且满足以下任意一个条件:\(x \& y > C\) ...
- ZOJ 2599 Graduated Lexicographical Ordering ★(数位DP)
题意 定义两个数的比较方法,各位数字之和大的数大,如果数字和相等则按字典序比较两个数的大小.输入n,k,求:1.数字k的排名:2.排名为k的数. 思路 算是一类经典的统计问题的拓展吧~ 先来看第一问. ...
- 数位dp相关
经典的数位Dp是要求统计符合限制的数字的个数. 一般的形式是:求区间[n,m]满足限制f(1). f(2). f(3)等等的数字的数量是多少. 条件 f(i) 一般与数的大小无关,而与数的组成有关. ...
- 2019牛客暑期多校训练营(第七场)H.Pair(数位dp)
题意:给你三个数A,B,C 现在要你找到满足 A and B >C 或者 A 异或 B < C 的对数. 思路:我们可以走对立面 把既满足 A and B <= C 也满足 A 异 ...
- 「算法笔记」数位 DP
一.关于数位 dp 有时候我们会遇到某类问题,它所统计的对象具有某些性质,答案在限制/贡献上与统计对象的数位之间有着密切的关系,有可能是数位之间联系的形式,也有可能是数位之间相互独立的形式.(如求满足 ...
- Codeforces - 55D Beautiful numbers (数位dp+数论)
题意:求[L,R](1<=L<=R<=9e18)区间中所有能被自己数位上的非零数整除的数的个数 分析:丛数据量可以分析出是用数位dp求解,区间个数可以转化为sum(R)-sum(L- ...
- BZOJ_3209_花神的数论题_组合数+数位DP
BZOJ_3209_花神的数论题_组合数+数位DP Description 背景 众所周知,花神多年来凭借无边的神力狂虐各大 OJ.OI.CF.TC …… 当然也包括 CH 啦. 描述 话说花神这天又 ...
- 数位dp入门 HDU 2089 HDU 3555
最基本的一类数位dp题,题目大意一般是在a~b的范围,满足某些要求的数字有多少个,而这些要求一般都是要包含或者不包含某些数字,或者一些带着数字性质的要求,一般来说暴力是可以解决这一类问题,可是当范围非 ...
随机推荐
- 【转】启动 Eclipse 弹出“Failed to load the JNI shared library jvm.dll”错误的解决方法! .
转载地址:http://blog.csdn.net/zyz511919766/article/details/7442633 原因1:给定目录下jvm.dll不存在. 对策:(1)重新安装jre或者j ...
- 测试Animation大型动画文件拆分播放的可行性
最近遇到一个问题,剧情动画文件大了复杂了之后,每次修改输出很麻烦,导出fbx就需要20分钟. 所以我想到了一个比较好的解决方法,在unity这边解决.把动画文件拆分成若干份,然后赋予不同的层并行播放 ...
- VMware 安装CentOS
使用VMware安装CentOS 6.4 环境:Windows7 , VMware Workstation10, CentOS6.4 为什么选择CentOS ? 主流: 目前的Linux操作系统主要应 ...
- 2016CCPC东北地区大学生程序设计竞赛 1005 HDU5926
链接http://acm.hdu.edu.cn/showproblem.php?pid=5926 题意:给我们一个矩阵,问你根据连连看的玩法可以消去其中的元素 解法:连连看怎么玩,就怎么写,别忘记边界 ...
- Android各种获取Context方法
首先讲一讲这四个函数的区别,后面还有我对context的一些理解区别如下所示: 原文链接http://stackoverflow.com/questions/6854265/getapplicatio ...
- program
[题目分析] 题目的意思是在一个数列中找到四个数,a[i]=a[j]<a[k]=a[l],其他都扯淡. 先把这些数sort一下,所有相等的数字就都排在一起了,然后这个数列可以按照数字的种类划分成 ...
- 样式其他与JS脚本语言
样式其他:display(显示block和隐藏none,不占位置) visibility(显示visible和隐藏hidden,占位置) overflow(超出范围 hidden隐藏) 透明(op ...
- 关于MYSQL group by 分组按时间取最大值的实现方法!
类如 有一个帖子的回复表,posts( id , tid , subject , message , dateline ) , id 为 自动增长字段, tid为该回复的主题帖子的id(外键关联), ...
- 30个实例详解TOP命令
Linux中的top命令显示系统上正在运行的进程.它是系统管理员最重要的工具之一.被广泛用于监视服务器的负载.在本篇中,我们会探索top命令的细节. AD: Linux中的top命令显示系统上正在运行 ...
- Android Handler Message总结
http://blog.csdn.net/caesardadi/article/details/8473777 当应用程序启动时,会开启一个主线程(也就是UI线程),由她来管理UI,监听用户点击,来响 ...