【背景】

在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的更多相关文章

  1. 数位dp踩坑

    前言 数位DP是什么?以前总觉得这个概念很高大上,最近闲的没事,学了一下发现确实挺神奇的. 从一道简单题说起 hdu 2089 "不要62" 一个数字,如果包含'4'或者'62', ...

  2. 【距离GDOI:141天】 滚入数位DP的坑

    作为博客园的第一篇...我都不知道要写什么了 ... 其实今天很没状态,就当吐槽吧... 嗯,被黄神带去写treap+可持久化线段树,然后在可持久化的删除上面跪了两天,真的是一跪不起.我已经连续多久没 ...

  3. # 数位DP入坑

    Hdu 2089 不要62 #include<iostream> #include<cstdio> #include<cmath> #include<cstr ...

  4. 浅谈数位DP

    在了解数位dp之前,先来看一个问题: 例1.求a~b中不包含49的数的个数. 0 < a.b < 2*10^9 注意到n的数据范围非常大,暴力求解是不可能的,考虑dp,如果直接记录下数字, ...

  5. 数位DP入门:(bzoj1833+3209)

    //我是来看文章创建时间的= = 膜拜了一下蔡大神.... 人生第一道自己写的数位DP...好吧以前是看题解然后也不知道为什么就过了的>_< 虽然说现在还是只会裸题= = 数位DP介绍: ...

  6. 数位dp初探

    我这种蒟蒻就一直不会写数位dp.. 于是开了个坑.. 1833: [ZJOI2010]count 数字计数 这道被KPM大爷说是入门题..嗯似乎找找规律然后减掉0的情况后乱搞就可以了..(但是还是写了 ...

  7. 数位dp小练

    最近刷题的同时还得填填坑,说来你们也不信,我还不会数位dp. 照例推几篇博客: 数位DP讲解 数位dp 的简单入门 这两篇博客讲的都很好,不过代码推荐记搜的形式,不仅易于理解,还短. 数位dp的式子一 ...

  8. uva12063数位dp

    辣鸡军训毁我青春!!! 因为在军训,导致很长时间都只能看书yy题目,而不能溜到机房鏼题 于是在猫大的帮助下我发现这道习题是数位dp 然后想起之前讲dp的时候一直在补作业所以没怎么写,然后就试了试 果然 ...

  9. 数位dp总结

    由简单到稍微难点. 从网上搜了10到数位dp的题目,有几道还是很难想到的,前几道基本都是模板题,供入门用. 点开即可看题解. hdu3555 Bomb hdu3652 B-number hdu2089 ...

随机推荐

  1. LINUX系统yum安装SVN服务及其配置

    待: http://oplinux.com/app/svn/linux-yum-install-svn.html  //基础设置及流程 http://files.cnblogs.com/logon/s ...

  2. 老师木发的makefile与autotools

    makefile http://scc.qibebt.cas.cn/docs/linux/base/%B8%FA%CE%D2%D2%BB%C6%F0%D0%B4Makefile-%B3%C2%F0%A ...

  3. HihoCoder 1097 Prim算法

    1097 : 最小生成树一·Prim算法 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 最近,小Hi很喜欢玩的一款游戏模拟城市开放出了新Mod,在这个Mod中,玩家可以 ...

  4. Eclipse环境搭建配置操作

    1.选择window 2.设置字体 3.设置编码格式:国际编码:UTF-8 第一个地方设置编码格式 第二个地方设置编码格式:这个更重要些 4.配置26个英文小写字母. 作用:能够在开发时提示你,快速开 ...

  5. plsql基本操作 复制表 导出表 导出表结构 及其导入

    上一片中介绍了安装instantclient +plsql取代庞大客户端的安装,这里说下plsql的基本操作 plsql操作界面图: 1.复制表 语句:create table IGIS_COPY a ...

  6. win键盘映射成mac键盘

    在win7系统下安装了mac虚拟机,mac的快捷键与win的键盘不一样,所以ctrl+c,ctrl+v都用不了,于是找方法映射. 搜索到 keyremap4macbook,,进到官网Karabiner ...

  7. VS2013 快捷方式

    1.查找空行:  使用正则表达式 ^\s\S*$\n

  8. Oracle创建实例

    1.打开database configuration assistant 2.下一步 3.下一步 4.完成 5.添加完密码后,点击关闭.  

  9. ORA-00845 : MEMORY_TARGET not supported on this system(调大数据库内存无法启动)

    问题描述:调大数据库内存后,启动数据库报 ORA-00845 : MEMORY_TARGET not supported on this system . -- 调大数据库内存后,数据库启动报错[ro ...

  10. ui-router 1.0以上的 $stateChangeStart

    ui-router transitionhooks 统一控制路由跳转, 前台控制如果没有登录就跳转到登录页面, 当然也可以在后台控制, 如果没有登录就返回对应的错误码, 然后在response中直接跳 ...