数位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的范围,满足某些要求的数字有多少个,而这些要求一般都是要包含或者不包含某些数字,或者一些带着数字性质的要求,一般来说暴力是可以解决这一类问题,可是当范围非 ...
随机推荐
- python怎么装模块
windows下 最简单的方法: File---Settings--Project ---Project Interpreter 下----点击 +号,输入你需要安装的模块名,点击Install P ...
- oracle查看表占磁盘大小
select segment_name, bytes/1024/1024 from user_segments S where S.segment_type = 'TABLE' AND S.segme ...
- Android本机号码及Sim卡状态的获取
SIM卡存储的数据可分为四类:第一类是固定存放的数据.这类数据在移动电话机被出售之前由SIM卡中心写入,包括国际移动用户识别号(IMSI).鉴权密钥(KI).鉴权和加密算法等等.第二类是暂时存放的有关 ...
- SDUT 2608:Alice and Bob
Alice and Bob Time Limit: 1000ms Memory limit: 65536K 有疑问?点这里^_^ 题目描述 Alice and Bob like playing ...
- 静态方法和类成员方法(Python)
静态方法和成员方法分别在创建时分别被装入Staticmethod 类型和 Classmethod类型的对象中.静态方法的定义没有 self参数,且能够被类本身直接调用,类方法在定义时需要名为 cls的 ...
- 2016 Al-Baath University Training Camp Contest-1 A
Description Tourist likes competitive programming and he has his own Codeforces account. He particip ...
- 位运算(bit)
位运算(bit) Time Limit:2000ms Memory Limit:64MB [题目描述] lyk最近在研究位运算.它发现除了xor,or,and外还有很多运算.它新定义了一种运算符“ ...
- CAShapeLayer
之前讲过CALayer动画相关知识,再来看看更加复杂的CAShapeLayer相关的动画知识. 普通CALayer在被初始化时是需要给一个frame值的,这个frame值一般都与给定view的boun ...
- Java获取某月天数
Java获取某月天数 Calendar cal = new GregorianCalendar(); //或者用Calendar cal = Calendar.getIns ...
- centos6.6 设置静态网络
[root@localhost ~]# vi /etc/sysconfig/network-scripts/ifcfg-eth0 DEVICE=eth0HWADDR=08:00:27:3D:5F:38 ...