beautiful numbers树形dp or 数位dp
题目找链接
题意:
如果数a能被a中的每一位数整除(0除掉),则称a是一个beautiful number,求一个区间内的beautiful numbers的个数。
分析:
首先,很显然,l到r的所有beautiful numbers(以下写b n吧,有点长)等于0到r的b n个数减去0到l-1的b n的个数,这个不用证明吧。当然也很好证。然后我们只要能在时间允许的范围内求0到某个数的b n的数量就可以了。
怎么求能?我们把它转化到树上,先举个例子:如果要求0到23的b n的数量,那么我们假设有一个根为0的树,0这个结点有儿子0 1 2,然后0有儿子0 1 2 3 4 5 6 7 8 9,1有儿子0 1 2 3 4 5 6 7 8 9,2有儿子0 1 2 3,那么我们只要从根开始读,一直读到叶子节点(例如一直向最左走我们就读到000,一直向最右走就读到023,然后中间可以读到这两个数中间所有的数,不重且不漏),到每一个叶子节点记录一下这个数可不可以被经过的所有节点整除就好了,这不还是暴力吗。。。先别急,慢慢来,这样我们先想一下怎么转移,如果他能被x,y整除,一定能被其最小公倍数整除,当然,反过来说也成立,那我们只需要记录途径数字的最小公倍数就可以直接判断这样走的数能不能被所有位数整除。我们定义Dp[i][ha][k]表示所有过第i个节点的b n数(当然已经给节点编号),ha表示我们已经读到的数,于是我们有了转移方程:
Dp[i][ha][k]=sum{Dp[son[i][ha*10+val[son[i][j]]][j]][divisor(k,val[son[i][j]])]};
就不写公式了,大家应该可以看懂,divisor表示最小公倍数,val[i]表示第i个节点上写的数字,son[i][j]表示第i个节点的第j个儿子。
其实到这里,基本的思路就有了,但是解决问题还差一点,首先,这么大的数组开不下,然后就是时间复杂度接受不了。于是我们要进行优化。
其实大家会发现,很多棵子数是相似的,那是不是有些子树可以只求一边呢,当然可以,首先我们要明确一点,我们所有可能用到的k都有x%2520同余x(mod k),于是我们想一想,如果到某个节点读出的数字是0252025200,其实和读到0000252000(位数要相等)最后找到的状态数没什么不同(前题是两个节点的子树都是满的),那么我们就可以把ha表示为读到的数字%2520,于是此时你会发现,这个点的b n的数量和这个点的i只没有什么关系,所有这一维可以省掉,但是还有问题,就是虽然0000同余00000(mod 2520)但是并不等价,为什么呢,因为子树大小已经不一样了(及还需读的位数不一样),那么我们就可应再加一维表示还要读的数字的数量,然后进行记忆话搜索就可以了。
现在再重新说一下状态:Dp[i][j][k]表示还剩i个数字没有读,读到的数字数字%2520为j且走过的所有的数的最小公倍数为k读完满的子树之后可以找到b n的数量。注意,刚才我并没有对k进行描述,但现在有了,因为刚才k并不是状态,只是记录一下到这里的最小公倍数,也就是说可以没有k这一维。而这里我们不再区分节点,所有要记录k,k相同才等价。(要想明白是为什么等价)
说到这里,大家应该都知道该怎么做了但是Dp数组仍然有点大,还能不能缩小一下,可以:离散化,k可以取到的值其实是要小于2520的,我们只要找出可能取到的值就可以了。
还有就是当然边界特殊处理。
最后是他的时间复杂度,有人说是O(玄学)。。。其实还是有保证的,首先,Dp中每个值只会算一次,边界最多18层,每层最多有10个儿子,而儿子只有一个是边界,所有还是可以保证复杂度的。
部分细节见代码注释。
最后看代码吧:
#include <cstdio>
#include <cstring>
long long Dp[][][];
int mod=;//1-9的最小公倍数
long long Gcd(long long a,long long b){
if(!b)
return a;
return Gcd(b,a%b);
}
long long B(long long a,long long b){//求最小公倍数
if(!a||!b)//特殊处理0
return a+b;
return (a/Gcd(a,b))*b;
}
int w[];//记录每一位以处理边界
int li[];
long long dp(int len,int yu,int BB,bool bi){//开始dp
if(len==){//到达叶子节点
if(yu%BB==)
return ;
else
return ;
}
if(!bi&&Dp[len][yu][li[BB]]!=-)//已经有等价情况处理过了
return Dp[len][yu][li[BB]];
int j;
if(bi)
j=w[len];
else
j=;
long long ans=;
for(int i=;i<j;i++)
ans+=dp(len-,(yu*+i)%mod,B(BB,i),);
ans+=dp(len-,(yu*+j)%mod,B(BB,j),bi);
if(!bi)
Dp[len][yu][li[BB]]=ans;
return ans;
}
long long Cl(long long a){
int len=;
while(a){
len++;
w[len]=a%;
a/=;
}
return dp(len,,,);//算出位数进行处理
}
int main(){
memset(Dp,-,sizeof(Dp));//0可能会tle,因为可能有0的一些节点要算好多遍
int t;
scanf("%d",&t);
int al=;
for(int i=;i<=;i++)//离散化
if(%i==){
al++;
li[i]=al;
}
for(int i=;i<=t;i++){
long long l,r;
scanf("%I64d%I64d",&l,&r);//题目说不用%lld
printf("%I64d\n",Cl(r)-Cl(l-));
}
return ;
}
beautiful numbers树形dp or 数位dp的更多相关文章
- BZOJ_1662_[Usaco2006 Nov]Round Numbers 圆环数_数位DP
BZOJ_1662_[Usaco2006 Nov]Round Numbers 圆环数_数位DP Description 正如你所知,奶牛们没有手指以至于不能玩“石头剪刀布”来任意地决定例如谁先挤奶的顺 ...
- 【BZOJ】1662: [Usaco2006 Nov]Round Numbers 圆环数(数位dp)
http://www.lydsy.com/JudgeOnline/problem.php?id=1662 这道题折腾了我两天啊-!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 果然 ...
- 数位dp初步——数位dp的两种方式
数位dp:一类统计区间[L,R]内某种符合规定的数字个数的题目.特征是R的范围会很大,O(N)范围内无法完成. 一般而言,解决这类题目有两种方式,一种是递推,另一种是记忆化搜索. 递推: 1)利用dp ...
- 区间DP,数位DP
dp(动态规划)顾名思义便是动态的一种规划,而这种规划往往会跟状态,状态转移方程,记忆化搜索扯上关系,当然DP也是各个OI考试的必考点和常考点,在毒瘤出题人的折磨下,出现了许许多多的动态规划,有线性, ...
- BestCoder Round #75 King's Order dp:数位dp
King's Order Accepts: 381 Submissions: 1361 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 655 ...
- CF908G New Year and Original Order(DP,数位 DP)
又一次降智…… (数位 DP 原来可以写这么短,学到了) 问题可以转化为求数位中 $\ge k$ 的有恰好 $j$ 位的数的个数.设为 $c_{j,k}$. 那么答案就是:(考虑把 $k$ 的贡献拆开 ...
- [Codefroces401D]Roman and Numbers(状压+数位DP)
题意:给定一个数,求将该数重新排列后mod m==0的方案数 重新排列就考虑到用到哪些数,以及此时mod m的值 于是dp[i][j]表示状态i中mod m==j的方案数 注意:转移的时候只要找到一种 ...
- SPOJ BALNUM Balanced Numbers 平衡数(数位DP,状压)
题意: 平衡树定义为“一个整数的某个数位若是奇数,则该奇数必定出现偶数次:偶数位则必须出现奇数次”,比如 222,数位为偶数2,共出现3次,是奇数次,所以合法.给一个区间[L,R],问有多少个平衡数? ...
- [转]数位dp小记
转载自:http://blog.csdn.net/guognib/article/details/25472879 参考: http://www.cnblogs.com/jffifa/archive/ ...
随机推荐
- html页面引用video.js播放m3u8格式视频
//head里面的内容,我是采用cdn引用的方式,因为项目太小 <head> <meta charset="utf-8" /> <title>二 ...
- DirectX11 With Windows SDK--31 阴影映射
前言 阴影既暗示着光源相对于观察者的位置关系,也从侧面传达了场景中各物体之间的相对位置.本章将起底最基础的阴影映射算法,而像复杂如级联阴影映射这样的技术,也是在阴影映射的基础上发展而来的. 学习目标: ...
- tab-switch 样式的添加 与 tab元素样式的切换
要点: 1.多个div类名相同情况下添加class样式 2.siblings() 方法返回被选元素的所有同级元素.DOM 树:该方法沿着 DOM 元素的同级元素向前和向后遍历. 3.利用索引,只添加当 ...
- String 的格式化
使用场景 用于生成redis等key-value 结构的key的格式化,方便管理 eg: String.format(RedisKeys.PURCHASE_ADD_BABY_LOCK,form.get ...
- Linux防火墙iptables详解
iptables详解(思维导图) 1. 概述 1.1 iptable简介 1.2 防火墙的种类 1.3 netfilter 2. iptables的工作流程 2.1 iptables工作图示 2.2 ...
- [AHOI2017/HNOI2017]单旋
题目 点这里看题目. 分析 最妙的地方在于,这道题其实是用一种数据结构模拟另一种数据结构! 我们需要维护深度和树的结构,以下对于每个操作进行分别讨论. 插入一个新节点 可以发现,这个新 ...
- [CF914D]Sum the Fibonacci
题目 点这里看题目. 分析 我们先放宽条件,重新定义五元组\((a,b,c,d,e)\)如下: 1.\(1\le a,b,c,d,e\le n\). 2.\(s_a\&s_b= ...
- 030.Kubernetes核心组件-Scheduler
一 Scheduler原理 1.1 原理解析 Kubernetes Scheduler是负责Pod调度的重要功能模块,Kubernetes Scheduler在整个系统中承担了"承上启下&q ...
- 安卓开发,Service 服务
Service 服务 是一种应用组件,可长时间后台运行,不提供用户界面.如音乐播放器/下载程序.不能自己运行. 使用Service的方式: (一)startService(): 调用者和服务之间没有联 ...
- EM(最大期望)算法推导、GMM的应用与代码实现
EM算法是一种迭代算法,用于含有隐变量的概率模型参数的极大似然估计. 使用EM算法的原因 首先举李航老师<统计学习方法>中的例子来说明为什么要用EM算法估计含有隐变量的概率模型参数. 假设 ...