算法复习——数位dp





开头由于不知道讲啥依然搬讲义
对于引入的这个问题,讲义里已经很清楚了,我更喜欢用那个建树的理解····
相当于先预处理f,然后从起点开始在树上走··记录目前已经找到了多少个满足题意的数k,如果枚举到第i位,下一位要走的是1,需要加上左子树的总数f[i-1][K-k],如果下一位走的是0直接走左子树即可····
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<ctime>
#include<cctype>
#include<cstring>
#include<string>
#include<algorithm>
using namespace std;
const int N=;
int f[N][N],x,y,k,b,num[N],n,ans1,ans2;
inline void pre()
{
for(int i=;i<=;i++)
{
f[i][]=f[i][i]=;
for(int j=;j<i;j++)
f[i][j]=f[i-][j]+f[i-][j-];
}
}
inline void trans(int x)
{
int temp=x;n=;
while(temp) num[++n]=temp%b,temp/=b;
}
inline int solve()
{
int tot=,sum=,i;
for(i=n;i>=;i--)
{
if(num[i]>) //大于1的话此时整个子树代表的数都是小于x的,因此直接统计答案
{
sum+=f[i][k-tot]; break;
}
else if(num[i]==)
{
sum+=f[i-][k-tot]; //等于1统计左儿子的答案(即小于该数且又有k个1的数的个数)
if(++tot>k) break;
}
}
if(i!=&&tot==k) sum++; //如果该数本身就符合答案的话答案加1
return sum;
}
int main()
{
//freopen("a.in","r",stdin);
pre();
scanf("%d%d%d%d",&x,&y,&k,&b);
trans(y),ans1=solve();
trans(x-),ans2=solve();
cout<<ans1-ans2<<endl;
return ;
}
例题:
1.windy数(bzoj1026)
Description
windy定义了一种windy数。不含前导零且相邻两个数字之差至少为2的正整数被称为windy数。 windy想知道,
在A和B之间,包括A和B,总共有多少个windy数?
Input
包含两个整数,A B。
Output
一个整数
Sample Input
1 10
【输入样例二】
25 50
Sample Output
9
【输出样例二】
20
HINT
【数据规模和约定】
100%的数据,满足 1 <= A <= B <= 2000000000 。
Source
首先运用数位dp的常规思想,用ans(B)-ans(A-1);
这道题我们用f[i][j][0/1]表示第j位为i且小于/大于原数前i为满足题意的数的个数,然后枚举上一位进行dp即可·····具体看代码··
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<ctime>
#include<cctype>
#include<cstring>
#include<string>
#include<algorithm>
using namespace std;
const int N=;
int f[N][N][],num[N],n,a,b;
inline int Abs(int a)
{
return a<?-a:a;
}
inline int solve(int x)
{
if(!x) return ;
n=;memset(f,,sizeof(f));int ans=;
while(x) num[++n]=x%,x/=;
for(int i=;i<=;i++)
if(i<=num[]) f[i][][]=;
else f[i][][]=;
for(int i=;i<=n;i++)
for(int j=;j<=;j++)
for(int k=;k<=;k++)
if(Abs(j-k)>=)
{
if(j<num[i]) f[j][i][]+=f[k][i-][]+f[k][i-][];
else if(j==num[i]) f[j][i][]+=f[k][i-][],f[j][i][]+=f[k][i-][];
else f[j][i][]+=f[k][i-][]+f[k][i-][];
}
for(int i=;i<=;i++)
{
ans+=f[i][n][];
if(i==num[n]) break;
}
for(int i=n-;i>=;i--)
for(int j=;j<=;j++)
ans+=f[j][i][]+f[j][i][];
return ans;
}
int main()
{
//freopen("a.in","r",stdin);
scanf("%d%d",&a,&b);
printf("%d\n",solve(b)-solve(a-));
return ;
}
2.不要62(hdu2089)
Problem Description
杭州交通管理局经常会扩充一些的士车牌照,新近出来一个好消息,以后上牌照,不再含有不吉利的数字了,这样一来,就可以消除个别的士司机和乘客的心理障碍,更安全地服务大众。
不吉利的数字为所有含有4或62的号码。例如:
62315 73418 88914
都属于不吉利号码。但是,61152虽然含有6和2,但不是62连号,所以不属于不吉利数字之列。
你的任务是,对于每次给出的一个牌照区间号,推断出交管局今次又要实际上给多少辆新的士车上牌照了。
Input
Output
Sample Input
0 0
Sample Output
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<ctime>
#include<cctype>
#include<cstring>
#include<string>
#include<algorithm>
using namespace std;
const int N=;
int f[N][N][],a,b,num[N],n,ans1,ans2;
inline int R()
{
char c;int f=;
for(c=getchar();c<''||c>'';c=getchar());
for(;c<=''&&c>='';c=getchar())
f=(f<<)+(f<<)+c-'';
return f;
}
inline void trans(int x)
{
memset(f,-,sizeof(f));
int temp=x;n=;
while(temp) n++,temp/=;
temp=x;
for(int i=n;i;i--)
num[i]=temp%,temp/=;
}
inline int dfs(int pos,int pre,bool jud)
{
if(pos==n+) return ;
if(f[pos][pre][jud]!=-) return f[pos][pre][jud];
int maxx=jud?num[pos]:,ans=;
for(int i=;i<=maxx;i++)
{
if(i==||(pre==&&i==)) continue;
ans+=dfs(pos+,i,jud&&i==maxx);
}
return f[pos][pre][jud]=ans;
}
int main()
{
while(true)
{
a=R(),b=R();
if(a==&&b==) break;
trans(a-);ans1=dfs(,,);
trans(b);ans2=dfs(,,);
cout<<ans2-ans1<<endl;
}
return ;
}
3.B-number(hdu3652)
Problem Description
Output
Sample Input
Sample Output
和上道题很像啊···只是需要在dfs时多加入一个mod和一个jud来判断是否整除和是否找到13即可·······
代码:
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<ctime>
#include<cctype>
#include<cstring>
#include<string>
#include<algorithm>
using namespace std;
const int N=;
int f[N][N][][][N],num[N],n,a;
inline void trans(int x)
{
memset(f,-,sizeof(f));
int temp=x;n=;
while(temp) temp/=,n++;
temp=x;
for(int i=n;i>=;i--) num[i]=temp%,temp/=;
}
inline int dfs(int pos,int mod,int jud,int lim,int pre)
{
if(pos==n+) return jud&&!mod;
if(f[pos][mod][jud][lim][pre]!=-) return f[pos][mod][jud][lim][pre];
int maxx=lim?num[pos]:,ans=,vmod,vjud;
for(int i=;i<=maxx;i++)
{
vmod=(mod*+i)%;vjud=jud;
if(pre==&&i==) vjud=;
ans+=dfs(pos+,vmod,vjud,lim&&i==maxx,i);
}
return f[pos][mod][jud][lim][pre]=ans;
}
int main()
{
//freopen("a.in","r",stdin);
while(scanf("%d",&a)!=EOF)
{
trans(a);
printf("%d\n",dfs(,,,,));
}
return ;
}
4.beautiful number(codeforces 55d)
题目描述
如果一个数能够被其每个除0的数位的数都整除,那么这个数就叫做美丽数。
给定一个区间 [x,y] ,计算该区间内有多少个美丽数。
输入格式
输入文件中有一行,为空格隔开的两个正整数 x 和 y(1≤x≤y≤9*1018)。
输出格式
输出一个整数,即区间 [x,y] 内的美丽数个数。
样例数据 1
输入
1 9
输出
9
样例数据 2
输入
12 15
输出
2
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<ctime>
#include<cctype>
#include<cstring>
#include<string>
#include<algorithm>
using namespace std;
const int N=;
int num[N],n,tot,hash[],id[];
long long dp[N][][][],x,y,ans1,ans2;
inline void pre()
{
for(int i=;i<=;i++)
if(!(%i)) hash[++tot]=i,id[i]=tot;
}
inline void trans(long long x)
{
memset(dp,-,sizeof(dp));
long long temp=x;n=;
while(temp) n++,temp/=;
temp=x;
for(int i=n;i>=;i--) num[i]=temp%,temp/=;
}
inline int gcd(int a,int b)
{
if(b==) return a;
else return gcd(b,a%b);
}
inline int getlcm(int a,int b)
{
return a*b/gcd(a,b);
}
inline long long dfs(int pos,int gbs,int mod,int lim)
{
if(pos==n+) return mod%hash[gbs]==;
if(dp[pos][gbs][mod][lim]!=-) return dp[pos][gbs][mod][lim];
int maxx=lim?num[pos]:;int vgbs,vmod;long long ans=;
for(int i=;i<=maxx;i++)
{
vmod=(mod*+i)%;vgbs=gbs;
if(i)
{
vgbs=getlcm(i,hash[gbs]);vgbs=id[vgbs];
}
ans+=dfs(pos+,vgbs,vmod,lim&&i==maxx);
}
return dp[pos][gbs][mod][lim]=ans;
}
int main()
{
// freopen("a.in","r",stdin);
pre();
scanf("%I64d%I64d",&x,&y);
trans(y);ans1=dfs(,,,);
trans(x-);ans2=dfs(,,,);
printf("%I64d",ans1-ans2);
return ;
}
算法复习——数位dp的更多相关文章
- 算法复习——数位dp(不要62HUD2089)
题目 题目描述 杭州人称那些傻乎乎粘嗒嗒的人为 62(音:laoer). 杭州交通管理局经常会扩充一些的士车牌照,新近出来一个好消息,以后上牌照,不再含有不吉利的数字了,这样一来,就可以消除个别的士司 ...
- 算法笔记--数位dp
算法笔记 这个博客写的不错:http://blog.csdn.net/wust_zzwh/article/details/52100392 数位dp的精髓是不同情况下sta变量的设置. 模板: ]; ...
- 【算法】数位 dp
时隔多日,我终于再次开始写博客了!! 上午听了数位 dp,感觉没听懂,于是在网上进行一番愉 ♂ 快 ♀ 的学习后,写篇博来加深一下印象~~ 前置的没用的知识 数位 不同计数单位,按照一定顺序排列,它们 ...
- 算法复习——区间dp
感觉对区间dp也不好说些什么直接照搬讲义了2333 例题: 1.引水入城(洛谷1514) 这道题先开始看不出来到底和区间dp有什么卵关系···· 首先肯定是bfs暴力判一判可以覆盖到哪些城市····无 ...
- 算法复习——树形dp
树形dp的状态转移分为两种,一种为从子节点到父节点,一种为父节点到子节点,下面主要讨论子节点到父亲节点的情况: 例题1(战略游戏): 这是一道典型的由子节点状态转移到父节点的问题,而且兄弟节点之间没有 ...
- 算法复习——背包dp
1.01背包 二维递推式子: 代码: ;i<=n;i++) ;x--) ][x-w[i]]+c[i],f[i-][x]); ][x]; printf("%d",f[n][m] ...
- 【HDU】6148 Valley Numer 数位DP
[算法]数位DP [题意]定义V-number为从左到看单位数字未出现先递增后递减现象的数字,求0~N中满足条件的数字个数.T<=200,lenth(n)<=100 [题解]百度之星201 ...
- 数位DP复习笔记
前言 复习笔记第五篇.(由于某些原因(见下),放到了第六篇后面更新)CSP-S RP++. luogu 的难度评级完全不对,所以换了顺序,换了别的题目.有点乱,见谅.要骂就骂洛谷吧,原因在T2处 由于 ...
- 算法-数位dp
算法-数位dp 前置知识: \(\texttt{dp}\) \(\texttt{Dfs}\) 参考文献 https://www.cnblogs.com/y2823774827y/p/10301145. ...
随机推荐
- AWVS12 防止反复注册
以管理员权限运行cmd,输入以下内容: cacls "C:\ProgramData\Acunetix\shared\license." /t /p everyone:r 如图:
- Android开发出现 StackOverflowError
问题:StackOverflowError 在HTC或者摩托罗拉的手机上测试出现 StackOverflowError 的错误. 06-12 10:28:31.750: E/AndroidRuntim ...
- 解决ubuntu上ifconfig没有eth0/ens33且无法上网的问题
ifconfig只有一个轮回端口lo,没有我们的网卡eth0,一开始以为是vsphere(新手对于vsphere不是很熟悉)上我的虚拟机配置问题,还查看了相关的网络配置,后来才知道是因为: 问题出在配 ...
- 201621123080《java程序设计》第14周实验总结
201621123080<java程序设计>第14周实验总结 1. 本周学习总结 1.1 以你喜欢的方式(思维导图或其他)归纳总结与数据库相关内容. 2. 使用数据库技术改造你的系统 2. ...
- MySQL_8.0.15_Windows10_X64 安装教程
最近学习的内容涉及到MySQL的知识,所以安装一个MySQL非常有必要,参考别人的教程安装过程还算顺利,其中遇到了一些问题查了一些也解决了,这里把整个安装过程梳理一遍,给大家一个参考. 我手里的电脑是 ...
- 22.Yii2.0框架多表关联一对一查询之hasOne
思路: 通过文章查它对应的分类信息 一对一的关系 控制器里 //一对一关联查询 public function actionRelatesone() { //方法一,hasOne() 用查一条文章的结 ...
- Post页面爬取失败__编码问题
python3爬取Post页面时, 报以下错误 "POST data should be bytes or an iterable of bytes. It cannot be of typ ...
- Linux之crond 服务介绍
在介绍crond之前,先科普一下什么是进程?什么是线程?什么是程序? 程序:程序是一组指令及参数的集合,指令按照既定的逻辑控制计算机运行.进程则是运行着的程序,是操作系统执行的基本单位.线程则是为了节 ...
- hierarchy viewer不能获取userbuild手机版本的UI布局
步骤很详细:http://maider.blog.sohu.com/255485243.html 其中的第7步命令需要更改为: java -jar smali-2.0.3.jar ./out -o c ...
- JAVA里的别名机制
别名现象主要出现在赋值的问题上: 对基本数据类型的赋值是很简单的.基本数据类型存储了实际的数值,而并非指向一个对象的引用,所以在为其赋值的时候,是直接将一个地方的内容复制到了另一个地方.例如,对基本数 ...