开坑数位dp
【背景】
在10月3日的dp专练中,压轴的第6题是一道数位dp,于是各种懵逼。
为了填上这个留存已久的坑,蒟蒻chty只能开坑数位dp了。
【例题一】[HDU2089]不要62
题目大意:给你一个区间[l,r],求区间内不含4和62的数的个数。
分析:首先 ans[l,r]=ans[0,r]-ans[0,l-1],这样成功将问题转化为了求区间[0,x]的答案,然后减一下即可。
然后可以预处理出一个f[][]数组,f[i][j]表示表示在i位数中以j开头的满足条件的数的个数,那么显然f[i][j]=sum{f[i-1][k]} (0<=k<=9&&j!=4&&!(j==6&&k==2))
然后用一个digit[]数组记录当前x从高位到低位的数字,如x=529,则digit[1]=5,digit[2]=2,digit[3]=9
最后从高到低按位累加答案即可。(这点不明白的可以看我的代码,毕竟有些东西只能意会,无法言传)
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<ctime>
using namespace std;
int n,m,digit[],f[][];
inline int read()
{
int x=,f=; char ch=getchar();
while(!isdigit(ch)) {if(ch=='-') f=-; ch=getchar();}
while(isdigit(ch)) {x=x*+ch-''; ch=getchar();}
return x*f;
}
void pre()
{
memset(f,,sizeof(f));
f[][]=;
for(int i=;i<=;i++)
for(int j=;j<=;j++)
for(int k=;k<=;k++)
if(j!=&&!(j==&&k==))
f[i][j]+=f[i-][k];
}
int ask(int x)
{
int len=,ans=;
while(x){digit[++len]=x%;x/=;}
digit[len+]=;
for(int i=len;i;i--)
{
for(int j=;j<digit[i];j++) if(j!=&&!(j==&&digit[i+]==)) ans+=f[i][j];
if(digit[i]==||(digit[i]==&&digit[i+]==)) break;
}
return ans;
}
int main()
{
//freopen("cin.in","r",stdin);
//freopen("cout.out","w",stdout);
pre();
while()
{
n=read(); m=read();
if(n==&&m==) break;
printf("%d\n",ask(m+)-ask(n));
}
return ;
}
【练习一】[bzoj1026]windy数
题目描述:windy定义了一种windy数。不含前导零且相邻两个数字之差至少为2的正整数被称为windy数。 windy想知道,在A和B之间,包括A和B,总共有多少个windy数?
建议这题自己想做法,其实和上面那道题差不多了。
如果你真的wa到受不了,参考代码:http://www.cnblogs.com/chty/p/5981569.html
【练习二】[hdu3555]bomb
题目大意:求给定区间的含有49的数的个数。
分析:我们可以转换一下思维,先求出区间内不含49的数的个数,然后用n减去这个数就行了,这就转化为了练习一的方法。(与网上其他题解不太一样,个人认为这种做法更简单)
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<ctime>
#include<algorithm>
using namespace std;
typedef long long ll;
ll T,digit[],f[][];
inline ll read()
{
ll x=,f=; char ch=getchar();
while(!isdigit(ch)) {if(ch=='-') f=-; ch=getchar();}
while(isdigit(ch)) {x=x*+ch-''; ch=getchar();}
return x*f;
}
void pre()
{
f[][]=;
for(ll i=;i<=;i++)
for(ll j=;j<=;j++)
for(ll k=;k<=;k++)
if(!(j==&&k==)) f[i][j]+=f[i-][k];
}
ll ask(ll x)
{
ll len=,ans=;
while(x) {digit[++len]=x%; x/=;}
digit[len+]=;
for(ll i=;i<len;i++)
for(ll j=;j<=;j++)
ans+=f[i][j];
for(ll i=;i<digit[len];i++) ans+=f[len][i];
for(ll i=len-;i;i--)
{
for(ll j=;j<digit[i];j++) if(!(digit[i+]==&&j==)) ans+=f[i][j];
if(digit[i+]==&&digit[i]==) break;
}
return ans;
}
int main()
{
//freopen("cin.in","r",stdin);
//freopen("cout.out","w",stdout);
T=read(); pre();
while(T--){ll n=read();printf("%I64d\n",n-ask(n+));}
return ;
}
【例题二】[poj3208]Apocalypse Someday
描述 Description
探险队员终于进入了金字塔。通过对古文字的解读, 他们发现,和《圣经》的作者想的一样,古代人认为 666 是属于魔鬼的数。不但如此,只要某数字的十进制表示中 有三个连续的 6,古代人也认为这个是魔鬼的数,比如 666,
1 666, 2 666, 3 666, 6 663, 16 666, 6 660 666 等等,统统是魔 鬼的数。
古代典籍经常用“第 X 大的魔鬼的数”来指代这些数。 这给研究人员带来了极大的不便。为了帮助他们,你需要写一个程序来求出这些魔鬼的数字。
题解详见http://blog.csdn.net/popoqqq/article/details/39319021
用上述方法写这道题的代码如下:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<ctime>
#include<algorithm>
using namespace std;
typedef long long ll;
ll T,S,f[][],digit[];
inline ll read()
{
ll x=,f=; char ch=getchar();
while(!isdigit(ch)) {if(ch=='-') f=-; ch=getchar();}
while(isdigit(ch)) {x=x*+ch-''; ch=getchar();}
return x*f;
}
void pre()
{
f[][]=;
for(ll i=;i<=;i++)
{
f[i][]=(f[i-][]+f[i-][]+f[i-][])*;
f[i][]=f[i-][];
f[i][]=f[i-][];
f[i][]=f[i-][]+f[i-][]*;
}
}
int getans(ll x)
{
ll len=,ans=,cnt=;
while(x) {digit[++len]=x%; x/=;}
for(ll i=len,j;i;i--)
{
ll sum;
for(int j=;j<=digit[i];j++)
{
if(cnt==) sum=;
else if(j==) sum=cnt+;
else sum=;
for(ll k=;k>=-sum;k--) ans+=f[i-][k];
}
if(cnt!=) cnt=(digit[i]==?cnt+:);
}
return ans;
}
int main()
{
//freopen("cin.in","r",stdin);
//freopen("cout.out","w",stdout);
T=read(); pre();
while(T--)
{
ll S=read(),l=,r=100000000000ll;
while(l+<r)
{
ll mid=(l+r)/;
if(getans(mid+)>=S) r=mid;
else l=mid;
}
if(getans(r)==S) printf("%I64d\n",l);
else printf("%I64d\n",r);
}
return ;
}
开坑数位dp的更多相关文章
- 数位dp踩坑
前言 数位DP是什么?以前总觉得这个概念很高大上,最近闲的没事,学了一下发现确实挺神奇的. 从一道简单题说起 hdu 2089 "不要62" 一个数字,如果包含'4'或者'62', ...
- 【距离GDOI:141天】 滚入数位DP的坑
作为博客园的第一篇...我都不知道要写什么了 ... 其实今天很没状态,就当吐槽吧... 嗯,被黄神带去写treap+可持久化线段树,然后在可持久化的删除上面跪了两天,真的是一跪不起.我已经连续多久没 ...
- # 数位DP入坑
Hdu 2089 不要62 #include<iostream> #include<cstdio> #include<cmath> #include<cstr ...
- 浅谈数位DP
在了解数位dp之前,先来看一个问题: 例1.求a~b中不包含49的数的个数. 0 < a.b < 2*10^9 注意到n的数据范围非常大,暴力求解是不可能的,考虑dp,如果直接记录下数字, ...
- 数位DP入门:(bzoj1833+3209)
//我是来看文章创建时间的= = 膜拜了一下蔡大神.... 人生第一道自己写的数位DP...好吧以前是看题解然后也不知道为什么就过了的>_< 虽然说现在还是只会裸题= = 数位DP介绍: ...
- 数位dp初探
我这种蒟蒻就一直不会写数位dp.. 于是开了个坑.. 1833: [ZJOI2010]count 数字计数 这道被KPM大爷说是入门题..嗯似乎找找规律然后减掉0的情况后乱搞就可以了..(但是还是写了 ...
- 数位dp小练
最近刷题的同时还得填填坑,说来你们也不信,我还不会数位dp. 照例推几篇博客: 数位DP讲解 数位dp 的简单入门 这两篇博客讲的都很好,不过代码推荐记搜的形式,不仅易于理解,还短. 数位dp的式子一 ...
- uva12063数位dp
辣鸡军训毁我青春!!! 因为在军训,导致很长时间都只能看书yy题目,而不能溜到机房鏼题 于是在猫大的帮助下我发现这道习题是数位dp 然后想起之前讲dp的时候一直在补作业所以没怎么写,然后就试了试 果然 ...
- 数位dp总结
由简单到稍微难点. 从网上搜了10到数位dp的题目,有几道还是很难想到的,前几道基本都是模板题,供入门用. 点开即可看题解. hdu3555 Bomb hdu3652 B-number hdu2089 ...
随机推荐
- Android快速开发-选项卡
介绍 几行代码实现Android选项卡界面,支持标准底部Tab自定义视图选项卡,头部文字选项卡. 底部自定义视图选项卡 先来看看实现下图中的效果我们代码应该怎么写? 实现上图效果只需以下代码: pub ...
- 如何在公司Http代理后使用NuGet官方源
文章转自CSDN 霍力强的专栏 有些公司上网使用的是Http代理.默认情况下,VS是无法访问外部网络的.如果要使用NuGet,通常只能在局域网里架一个自己的NuGet服务器.但这种方法不论是packa ...
- 【数据库】SQLite学习
http://www.cnblogs.com/fnng/archive/2013/05/26/3099547.html
- W3Schools SQL Quiz
W3Schools SQL Quiz SQL QUIZ Points: 25 out of 25 1. What does SQL stand for? You answered: Structure ...
- Android Socket编程
花了大概两天的时间,终于把Android的Socket编程给整明白了.抽空和大家分享一下: Socket Programming on Android Socket 编程基础知识: 主要分服务器端编程 ...
- Chrome 的审查元素功能有哪些奇技淫巧
学习地址: https://www.zhihu.com/question/34682699
- 解决eclipse Blocked : the user operation is waiting
本文转载自:http://blog.csdn.net/shaw1994/article/details/44106679 出现这种情况的时候整个adb都跪了, eclipse一run就会跪, 而且还容 ...
- Uploadify在asp.net下使用Demo
为了使自己以后不再去网上搜索,特记录下来 从uploadify官网http://www.uploadify.com/上下载文件 必要的文件: 1.jquery的js文件 2.jquery.upload ...
- java代码Calendar类
总结:时间类Calendar.类代表当前时 Calendar c=Calendar.getInstance();,,Calendar是抽象类.Calendar的构造方法是私有的,API提供了getIn ...
- 分布式缓存系统 Memcached 状态机之网络数据读取与解析
整个状态机的基本流程如下图所示,后续分析将按该流程来进行. 接上节分解,主线程将接收的连接socket分发给了某工作线程,然后工作线程从任务队列中取出该连接socket的CQ_ITEM,开始处理该连接 ...