算法复习——数位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. ...
随机推荐
- CF Gym 100187J Deck Shuffling (dfs判连通)
题意:给你一堆牌,和一些洗牌机,可以改变牌的顺序,问你能不能通过洗牌机把数字为x的牌洗到第一个位置. 题解:反向建边,dfs判断连通性 #include<cstdio> #include& ...
- ios常见错误之 Failed to instantiate the default view controller for UIMainStoryboardFile 'Main' - perhaps the designated entry point is not set?
Failed to instantiate the default view controller for UIMainStoryboardFile 'Main' - perhaps the desi ...
- xpath定位和css定位对比
xpath定位和css定位对比 实际项目中使用较多的是xpath定位和css定位.XPath是XML文档中查找结点的语法,换句话就是通过元素的路径来查找这个元素.xpath比较强大,而css选择器 ...
- Bootstrap历练实例:默认的列表组
Bootstrap 列表组 本章我们将讲解列表组.列表组件用于以列表形式呈现复杂的和自定义的内容.创建一个基本的列表组的步骤如下: 向元素 <ul> 添加 class .list-grou ...
- Eclipse+Tomcat搭建jsp服务器
首先,安装java sdk 环境,这里就不多说了,附上java sdk的下载地址:http://www.oracle.com/technetwork/java/javase/downloads/jdk ...
- Roman Numeral Converter-freecodecamp算法题目
Roman Numeral Converter 1.要求 将给定的数字转换成罗马数字 所有返回的罗马数字都应该是大写形式 2.思路 分别定义个位.十位.百位.千位的对应罗马数字的数组 用Math.fl ...
- 八皇后问题(DFS)
题目描述: 要在国际象棋棋盘中放八个皇后,使任意两个皇后都不能互相吃,皇后能吃同一行.同一列,同一对角线上(两个方向的对角线)的任意棋子.现在给一个整数n(n<=92),输出前n种的摆法. 输入 ...
- 03大端和小端(Big endian and Little endian)
1.大端和小端的问题 对于整型.长整型等数据类型,Big endian 认为第一个字节是最高位字节(按照从低地址到高地址的顺序存放数据的高位字节到低位字节),而 Little endian 则相反 ...
- Django之用户认证
用户认证组件简介 功能:用session记录登录验证状态 前提:必须使用django自带的auth_user表.那这里有的同学就会有疑问了,自己不能创建自己的用户表吗? 当然可以,用户认证组件虽然只针 ...
- python数据类型之字符串(str)和其常用方法
字符串是有序的,不可变的. 下面的例子说明了字符串是不可变的 name = 'alex' name = 'Jack' """ 并没有变,只是给name开启了一块新内存,储 ...