算法复习——数位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. ...
随机推荐
- C# 使用Epplus导出Excel [5]:样式
C# 使用Epplus导出Excel [1]:导出固定列数据 C# 使用Epplus导出Excel [2]:导出动态列数据 C# 使用Epplus导出Excel [3]:合并列连续相同数据 C# 使用 ...
- ubuntu 16.04 + 中文输入法
在桌面右上角设置图标中找到"System Setting",双击打开. 在打开的窗口里找到"Language Support",双击打开. 可能打开会说没有安装 ...
- VMware12全新安装CentOS-6.9模板机(已优化)
1.从安装系统开始准备 安装中添加网卡 eth0 ip 10.0.0.210 netmask 24 gateway 10.0.0.254 DNS servers 223.5.5.5 eth1 ip 1 ...
- C++图书馆管理系统项目中部分功能代码实现(书籍推荐)
bool UserServiceImpl::Compare1(Book b1,Book b2)//按照借阅次数比较{ if(b1.GetCnt() > b2.GetCnt()) { return ...
- python向上取整 向下取整
向上取整 ceil() 函数返回数字的向上取整整数,就是返回大于等于变量的最近的整数. ceil()是不能直接访问的,需要导入 math 模块. import math math.ceil( x ) ...
- Survey lists 10 most innovative cities
From China Daily Beijing and Shanghai are among the 10 most innovative cities in the world, based on ...
- Linux学习-CentOS 7.x 预设启动的服务简易说明
这里 仅介绍几个很常见的 daemons 而已,更多的信息呢,就得要麻烦你自己使用 systemctl list-unit-files --type=service 去查询.底下的建议主要是针对 Li ...
- MySQL数据库详解(一)执行SQL查询语句时,其底层到底经历了什么?
一条SQL查询语句是如何执行的? 前言 大家好,我是WZY,今天我们学习下MySQL的基础框架,看一件事千万不要直接陷入细节里,你应该先鸟瞰其全貌,这样能够帮助你从高维度理解问题.同样,对于MyS ...
- luogu2158 [SDOI2008]仪仗队 欧拉函数
点 $ (i,j) $ 会看不见当有 $ k|i $ 且 $ k|j$ 时. 然后就成了求欧拉函数了. #include <iostream> #include <cstring&g ...
- kruskal - 倍增 - 并查集 - Luogu 1967 货车运输
P1967 货车运输 题目描述 A 国有 n 座城市,编号从 1 到 n,城市之间有 m 条双向道路.每一条道路对车辆都有重量限制,简称限重.现在有 q 辆货车在运输货物, 司机们想知道每辆车在不超过 ...