今天去牛客网看了看 包含一 这道题,一开始没看清,以为它要统计 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'的个数的更多相关文章

  1. ACM学习历程—HDU5587 Array(数学 && 二分 && 记忆化 || 数位DP)(BestCoder Round #64 (div.2) 1003)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5587 题目大意就是初始有一个1,然后每次操作都是先在序列后面添加一个0,然后把原序列添加到0后面,然后 ...

  2. 2019牛客多校第六场H Pair(数位DP 多个数相关)题解

    题意: 传送门 给你\(A,B,C\),要求你给出有多少对\((x, y)\)满足\(x\in [1,A],y\in [1,B]\),且满足以下任意一个条件:\(x \& y > C\) ...

  3. ZOJ 2599 Graduated Lexicographical Ordering ★(数位DP)

    题意 定义两个数的比较方法,各位数字之和大的数大,如果数字和相等则按字典序比较两个数的大小.输入n,k,求:1.数字k的排名:2.排名为k的数. 思路 算是一类经典的统计问题的拓展吧~ 先来看第一问. ...

  4. 数位dp相关

    经典的数位Dp是要求统计符合限制的数字的个数. 一般的形式是:求区间[n,m]满足限制f(1). f(2). f(3)等等的数字的数量是多少. 条件 f(i) 一般与数的大小无关,而与数的组成有关. ...

  5. 2019牛客暑期多校训练营(第七场)H.Pair(数位dp)

    题意:给你三个数A,B,C 现在要你找到满足  A and B >C 或者 A 异或 B < C 的对数. 思路:我们可以走对立面 把既满足 A and B <= C 也满足 A 异 ...

  6. 「算法笔记」数位 DP

    一.关于数位 dp 有时候我们会遇到某类问题,它所统计的对象具有某些性质,答案在限制/贡献上与统计对象的数位之间有着密切的关系,有可能是数位之间联系的形式,也有可能是数位之间相互独立的形式.(如求满足 ...

  7. Codeforces - 55D Beautiful numbers (数位dp+数论)

    题意:求[L,R](1<=L<=R<=9e18)区间中所有能被自己数位上的非零数整除的数的个数 分析:丛数据量可以分析出是用数位dp求解,区间个数可以转化为sum(R)-sum(L- ...

  8. BZOJ_3209_花神的数论题_组合数+数位DP

    BZOJ_3209_花神的数论题_组合数+数位DP Description 背景 众所周知,花神多年来凭借无边的神力狂虐各大 OJ.OI.CF.TC …… 当然也包括 CH 啦. 描述 话说花神这天又 ...

  9. 数位dp入门 HDU 2089 HDU 3555

    最基本的一类数位dp题,题目大意一般是在a~b的范围,满足某些要求的数字有多少个,而这些要求一般都是要包含或者不包含某些数字,或者一些带着数字性质的要求,一般来说暴力是可以解决这一类问题,可是当范围非 ...

随机推荐

  1. python 补充-decode和encode

    1. decode与encode转码 在Python3中默认编码就是uncode,encode转成Byte类型 在Python2中默认编码就是ascii window下默认编码是GBK decode( ...

  2. Python 深拷贝和浅拷贝

    Python中,对象的赋值,拷贝(深/浅拷贝)之间是有差异的,如果使用的时候不注意,就可能产生意外的结果. 下面本文就通过简单的例子介绍一下这些概念之间的差别. 对象赋值 直接看一段代码: will= ...

  3. 杭电1170 Balloon Comes

    Problem Description The contest starts now! How excited it is to see balloons floating around. You, ...

  4. c#读取Excel的列名问题

    在修改c#读取Excel的时候,遇到了一些小问题,总结下,希望别人不用再浪费时间 读取excel的时候,如果是空行就不读取? SELECT * FROM [DB_ESTATE$] where F2&l ...

  5. 【转】MYSQL入门学习之五:MYSQL的字符集

    转载地址:http://www.2cto.com/database/201212/175541.html MySQL的字符集支持(Character Set Support)有两个方面:字符集(Cha ...

  6. YTU 3002: 出栈顺序(栈和队列)

    3002: 出栈顺序(栈和队列) 时间限制: 1 Sec  内存限制: 128 MB 提交: 80  解决: 20 题目描述 给出一个入栈序列,和一个出栈序列,判断该出栈序列是否正确. 输入 输入包含 ...

  7. Javascript中最常用的经典技巧

    1. oncontextmenu="window.event.returnValue=false" 将彻底屏蔽鼠标右键<table border oncontextmenu= ...

  8. HttpConnection方式访问网络

    参考疯狂android讲义,重点在于学习1.HttpConnection访问网络2.多线程下载文件的处理 主activity: package com.example.multithreaddownl ...

  9. 使用 Filter 完成一个简单的权限模型

    ****对访问进行权限控制: 有权限则可以访问, 否则提示: 没有对应的权限, 请 返回其访问者的权限可以在manager那进行设置:

  10. MUI 个推

    个推 四种消息模板(透传消息模板.点击通知打开网页模板.点击通知打开应用模板.点击通知栏弹框下载模版) 三种推送方式(对单个用户推送接口 | 对指定用户列表推送接口 | 对指定应用群推接口) 四种消息 ...