算法复习——数位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. ...
随机推荐
- Python-OpenCV——Morphological Transformations(形态学转换)
目标 这一节 我们将学习不同的形态学操作,如腐蚀.膨胀.开.闭...... 我们将看到不同的函数,如:cv2.erode().cv2.dilate().cv2.morphology() 理论 形态变换 ...
- python 基础之while无限循环
用户登录程序 username = "chenxi" passwed = "testki" counter = 0 while counter < 3: ...
- python基础一 day15 复习
迭代器和生成器迭代器 可迭代协议 —— 含有iter方法的都是可迭代的 迭代器协议 —— 含有next和iter的都是迭代器 特点 节省内存空间 方便逐个取值,一个迭代器只能取一次.生成器 —— 迭代 ...
- JavaScript -- 内置对象字符串
charAt和charCodeAt charAt语法: stringObject.charAt(index) 功能: 返回stringObject中index位置的字符. charCodeAt语法 s ...
- iOS开发遇到的坑之六--使用cocopods管理第三方库时,编译出现Library not found for -lPods问题的解决办法
在项目中有时候会遇到Library not found for -lPods(这里的IPods指的是你具体的第三方库)的问题 出现这个错误的原因是:xcode在编译的时候找不到这个库,从而导致项目无法 ...
- 如何将字符串@“ abc123.xyz789”倒置
#import <Foundation/Foundation.h> int main(int argc, const char * argv[]) { @autoreleasepool { ...
- iOS中的数据存储方式_SQLite3
优点: 1) SQLite是一款轻型的嵌入式数据库; 2) 它占用资源非常的低,在嵌入式设备中,可能只需要几百K的内存就够了 3) 它的处理速度比Mysql.PostgreSQL这两款著名的数据库都还 ...
- [已解决] odoo12 菜单不显示,安装后多出菜单
描述:odoo11中自定义模块写的,除了res.partner,res.users使用odoo自带的.其他的写了一个中国城市l10n_cn_city模型,一个账单模型(继承l10n_cn_city). ...
- Python学习笔记(一):基础知识
一.什么是python? python是一种面向对象.解释型的计算机语言,它的特点是语法简洁.优雅.简单易学 二.编译型语言和解释型语言 编译型语言就是把程序编译成计算机语言然后执行,(一次编译到处运 ...
- 【HIHOCODER 1589】回文子串的数量(Manacher)
描述 给定一个字符串S,请统计S的所有|S| * (|S| + 1) / 2个子串中(首尾位置不同就算作不同的子串),有多少个是回文字符串? 输入 一个只包含小写字母的字符串S. 对于30%的数据,S ...