构造+数位dp
题意:给定正整数a,b,k,你的任务是在所有满足a<=n<=b中的整数n中,统计有多少个满足n自身是k的倍数,且n的各位数字之和也是k的倍数。
【思路】
这种题的固定套路是设f(x)为[0,x]中满足题意的解的个数,那么本题的答案就是f(b)-f(a-1)。关键问题就是求解f函数。因为数据范围太大,无法穷举,所以这道题要用分段求和的思想来解决问题。比如说要求解f(3212),那么就把[0,3212]拆分出来,也就是
第一部分 0***,1***,2****
第二部分 30**,31**
第三部分 320*
第四部分 3210,3211,3212
(*表示0-9任意一个数)
然后分别求解求和,求解时用到数位dp,设dp(d,m1, m2)表示有d位*,各位数字和%k==m1,整体%k==m2,那么现在考虑它的递推式。假设d位*中的最高位是x,那么现在的数字就是x****…*(d-1个*),设后面d-1个*的各位数字之和为a,整体为b,那么(x+a)%k=m1, (x*10^(d-1)+b)%k=m2
反解出a%k=((m1-x)%k+k)%k, b%k=((m2-10^(d-1)*x)%k+k)%k
所以递推公式就是dp(d,m1, m2)=sum{dp(d-1, a%k, b%k)} (0<=x<=9)
对递归结束条件d==0时的解有两种理解方法
<1>当d==1时,即dp(1,m1,m2)将d==1代入可得a%k=((m1-x)%k+k)%k, b%k=((m2-x)%k+k)%k。而对dp(1,m1,m2)来说,只有一个*,位数和和自身相等,如果m1!=m2,那么dp(1,m1,m2)=0,如果m1==m2,那么当x%k==m1时即x=ck+m1即(m1-x)%k=0即a%k=0,b%k=0时有一组对应解。所以dp(0,m1,m2)==1(m1=0, m2=0),其他情况dp(0,m1, m2)==0。
<2>其实直观的去想,当d==0时一个*也没有,表示的就是数字0,而0对任何数求余还是0,所以当m1==m2==0的时候,0符合条件dp(0,m1,m2)==1,否则为0。
还有一个细节要注意就是虽然k的范围是[1,10000]但是由于a,b都在int范围内,所以位数和最大不会超过82,当k>82以后,无论如何一个int整数的各位数字之和 mod k != 0,也就是无解,直接输出0即可。
最后就是f(x)的计算了,把x的每一位都存储起来,低位在前。通过模拟的方式,用bitsum记录之前已经积累的位数和,sum记录之前已经累计的整体和,具体的细节还要在代码中体现。
#include<bits/stdc++.h>
using namespace std; const int pw[] = { , , , , , , , , , }; int a, b, k;
int dp[][][];
int bit[]; int dfs(int d, int m1, int m2) {
if ( == d) return dp[d][m1][m2] = (m1 == && m2 == ) ? : ;//关键!
if (- != dp[d][m1][m2]) return dp[d][m1][m2]; int ans = ;
for (int x = ; x <= ; x++) {
ans += dfs(d - , ((m1 - x) % k + k) % k, ((m2 - x*pw[d-]) % k + k) % k);
}
return dp[d][m1][m2] = ans;
} int f(int x) {//求出[0,x]中符合题意的数的个数 if ( == x) return ;//特例,0对任何数求余都是0 //按位存储数字
int cpy = x, size = ;
memset(bit, , sizeof(bit));
while (cpy) {
bit[size++] = cpy % ;
cpy /= ;
} int ans = ;
int bitsum = ;//位数和
int sum = ;//整体和 for (int i = size - ; i >= ; i--) {
if (i) {
for (int j = ; j < bit[i]; j++) {
ans += dfs(i, (k-(bitsum+j)%k )%k, (k- (sum+j*pw[i])%k )%k );
//ans += dfs(i, ((-(bitsum+j))%k + k)%k , ((-(sum+j*pw[i]))%k + k)%k );
//两种写法,同模的式子正确即可
}
}
else {
for (int j = ; j <= bit[i]; j++) {//个位,可以取到最大值
ans += dfs(i, (k-(bitsum+j)%k )%k, (k- (sum+j*pw[i])%k )%k );
}
}
bitsum += bit[i];//及时更新
sum += bit[i]*pw[i];
} return ans;
} int main() {
int t;
scanf("%d", &t);
while (t--) {
scanf("%d%d%d", &a, &b, &k);
if (k > ) { printf("0\n"); }
else {
memset(dp, -, sizeof(dp));
int ans = f(b) - f(a - );
printf("%d\n", ans);
}
}
return ;
}
构造+数位dp的更多相关文章
- 蒟蒻的数位DP专题总结
BZOJ 1026: [SCOI2009]windy数: 题目链接: http://www.lydsy.com/JudgeOnline/problem.php?id=1026 d ...
- 数位DP之奥义
恩是的没错数位DP的奥义就是一个简练的dfs模板 int dfs(int position, int condition, bool boundary) { ) return (condition ? ...
- SRM 510 2 250TheAlmostLuckyNumbersDivTwo(数位dp)
SRM 510 2 250TheAlmostLuckyNumbersDivTwo Problem Statement John and Brus believe that the digits 4 a ...
- 数位DP之小小结
资料链接:http://wenku.baidu.com/view/9de41d51168884868662d623.html http://wenku.baidu.com/view/d2414ffe0 ...
- 动态规划——数位dp
通过先前在<动态规划——背包问题>中关于动态规划的初探,我们其实可以看到,动态规划其实不是像凸包.扩展欧几里得等是具体的算法,而是一种在解决问题中决策的思想.在不同的题目中,我们都需要根据 ...
- HUST 1569(Burnside定理+容斥+数位dp+矩阵快速幂)
传送门:Gift 题意:由n(n<=1e9)个珍珠构成的项链,珍珠包含幸运数字(有且仅由4或7组成),取区间[L,R]内的数字,相邻的数字不能相同,且旋转得到的相同的数列为一种,为最终能构成多少 ...
- 数位dp初探
我这种蒟蒻就一直不会写数位dp.. 于是开了个坑.. 1833: [ZJOI2010]count 数字计数 这道被KPM大爷说是入门题..嗯似乎找找规律然后减掉0的情况后乱搞就可以了..(但是还是写了 ...
- HDU - 4389 X mod f(x)(数位dp)
http://acm.hdu.edu.cn/showproblem.php?pid=4389 题意 为[A,B] 区间内的数能刚好被其位数和整除的数有多少个. 分析 典型的数位dp...比赛时想不出状 ...
- 【poj3252】 Round Numbers (数位DP+记忆化DFS)
题目大意:给你一个区间$[l,r]$,求在该区间内有多少整数在二进制下$0$的数量$≥1$的数量.数据范围$1≤l,r≤2*10^{9}$. 第一次用记忆化dfs写数位dp,感觉神清气爽~(原谅我这个 ...
随机推荐
- Web RTC录视频
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- Leetcode代码复盘_动态规划
动态规划中包含3个重要的概念: 1.最优子结构 2.边界 3.状态转移公式 以跳台阶为例,最优子结构为f(10)=f(9) + f(8),边界是f(1)=1, f(2)=2,状态转移公式f(n)=f( ...
- 关于java使用json不能够使用报没有导包的问题,以及前后台交互json数据的使用
博客搬迁,给你带来的不便,敬请谅解! http://www.suanliutudousi.com/2017/12/02/%e5%85%b3%e4%ba%8ejava%e4%bd%bf%e7%94%a8 ...
- docker--build base image
通过dockerfile build一个base image,在上面运行一个c程序 首先 1.创建一个目录. 2.然后创建一个c写的小程序,并且gcc编译好. 3.创建一个Dockerfile FRO ...
- miaosha
1:跨域请求配置 后端Controller 添加注解 @CrossOrigin(origins = {"*"},allowCredentials = "true" ...
- java爬取读者文摘杂志
java爬虫入门实战练习 此代码仅用于学习研究 此次练习选择了读者文摘杂志网站进行文章爬取 练习中用到的都只是一些简单的方法,不过过程中复习了输入流输出流的使用以及文件的创建写入等知识,对自己还是有所 ...
- 路过--<全世界谁倾听你>
这首歌大概就是说男生和女生分手了男生一直忘不了女生给他带来的感觉(那种只有那个女生才能给男生带来的喜欢)就算黄昏 还是清晨 男生是男生的清晨 女生是女生的黄昏两个人没有交集了就算雨和歌都停了 风还是会 ...
- 关于solarwinds的一些介绍
由于是给客户使用,作为运维人员自然是要安装测试一下的. solarwinds是一个付费的监控软件,部署起来很方便,加agent节点也很方便,除了监控主机,还可以监控网络流量,交换机等设备.由于并没有实 ...
- Codeforces 343E 最小割树
题意及思路:https://www.cnblogs.com/Yuzao/p/8494024.html 最小割树的实现参考了这篇博客:https://www.cnblogs.com/coder-Uran ...
- #define和const的区别(转)
这个区别用从几个角度来说: 角度1:就定义常量说的话:const 定义的常数是变量 也带类型, #define 定义的只是个常数 不带类型. 角度2:就起作用的阶段而言:define是在编译的预处理阶 ...