因为这几天写的几道数位DP大多都太水。。而且也确实没什么好讲所以就扔到一起了。

[hdu4772]Good Numbers

  要求统计区间内 各位数之和能被10整除 的数的个数。

  练手,f[i][j][k]表示i位的数,以j开头,各位数之和取模10的结果为k,的方案数。

 #include<cstdio>
#include<iostream>
#include<cstring>
#define ll long long
using namespace std;
int i,j,j1,k,k1,n,m;
ll f[][][],ten[],l,r; int s[],len;
inline ll get(ll x){
if(x<)return ;
int i,j,k,pre;ll tmp,ans=;
for(i=;i<=;i++)if(x==ten[i]){x--;break;}
if(!x)return ;
for(tmp=x,len=;tmp;tmp/=)s[++len]=tmp%; for(i=;i<len;i++)for(j=;j<=;j++)ans+=f[i][j][];
for(i=;i<s[len];i++)ans+=f[len][i][]; for(pre=s[len],i=len-;i;i--){
k=(-pre+)%;
for(j=;j<s[i];j++)ans+=f[i][j][k];
pre=(pre+s[i])%;
}
return ans+(pre==)+;
}
int main(){
for(i=ten[]=;i<=;i++)ten[i]=ten[i-]*;
for(i=;i<=;i++)f[][i][i]=;
for(i=;i<=;i++)
for(j=;j<=;j++)for(k=;k<=;k++)
for(j1=,k1=(k-j+)%;j1<=;j1++)f[i][j][k]+=f[i-][j1][k1]; for(scanf("%d",&m),n=;n<=m;n++){
scanf("%lld%lld",&l,&r);
printf("Case #%d: %lld\n",n,get(r)-get(l-));
}
return ;
}

[hdu2089]不要62

  要求统计区间内有多少个数 不包含62并且不包括4.

  f[i][j]表示i位的数,以j开头,非法数字的个数。

 #include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
int f[][],ten[],sum;
int i,j,k,n,m;
int now[];
inline int get(int x){
if(!x)return ;
int i,len=,ans=;
for(int tmp=x;tmp;tmp/=)now[++len]=tmp%;
now[len+]=;
for(i=len;i;i--){
for(j=;j<now[i];j++){
ans+=f[i][j];//,printf("add: %d %d\n",i,j);
if(j==&&now[i+]==)ans+=ten[i-]-f[i][j];
}
if(now[i]==||(now[i]==&&now[i+]==)){ans+=x%ten[i-]+;break;}
}
// printf("%d ans:%d\n",x,ans);
return ans;
}
int main(){
for(i=;i<=;i++)f[][i]=i==;
ten[]=,ten[]=;
for(i=;i<=;i++){
ten[i]=ten[i-]*;
for(j=sum=;j<=;j++)sum+=f[i-][j];
for(j=;j<=;/*printf("%d %d %d\n",i,j,f[i][j]),*/j++)
if(j==)f[i][j]=ten[i-];
else if(j==)f[i][j]=sum+ten[i-]-f[i-][];
else f[i][j]=sum;
}
while(scanf("%d",&n)==){
scanf("%d",&m);
if(!n&&!m)break;
printf("%d\n",m-n+-(get(m)-get(n-)));
}
return ;
}

[hdu3555]bomb

  要求统计区间内有多少个包含49的数。

  f[i][j]表示i位的数,j开头,包含49的数的个数。(因为49这个数比较特殊一点(9是最大的数)...统计的时候可以不写关于第二位数的特判)

 #include<cstdio>
#include<iostream>
#include<cstring>
#define ll long long
using namespace std;
ll f[][],ten[];
int i,j,len,s[];
ll tmp,n;
inline ll get(ll x){
ll ans=;
for(len=,tmp=x;tmp;tmp/=)s[++len]=tmp%;s[len+]=;
for(i=;i<len;i++)for(j=;j<=;j++)ans+=f[i][j];
for(i=len;i;i--){
for(j=i==len;j<s[i];j++)ans+=f[i][j];
if(s[i]==&&s[i+]==){ans+=x%ten[i-]+;break;}
}
return ans;
}
int main(){
for(i=ten[]=;i<=;i++)ten[i]=ten[i-]*(ll);
for(i=;i<=;i++)
for(j=;j<=;/*printf("%d %d %lld\n",i,j,f[i][j]),*/j++)
if(j!=&&i>)f[i][j]=f[i-][j]*+f[i-][];
else f[i][j]=f[i-][]*+f[i-][]+ten[i-];
int T;
for(scanf("%d",&T);T;T--)
scanf("%lld",&n),printf("%lld\n",get(n));
return ;
}

[hdu4507]恨7不成妻

  预处理的时候,数字的平方和可以通过 方案数、数字和、数字的平方和 三个玩意算出来。。算是常见姿势了吧。

  再具体点见代码注释

 #include<cstdio>
#include<iostream>
#include<cstring>
#define ll long long
using namespace std;
const int modd=;
struct zs{
ll num,sum,sqr;//方案数,方案的数字和,平方和
}f[][][][][];//f[i][x][j][k][l]:i位的数,开头数字为x,j表示有无某一位为7,k表示每一位加起来的和%7的值,l表示数字%7的值。
ll ten[];
ll l,r; inline void add(zs &a,zs b,ll num){
num%=modd;
a.num+=b.num,a.sum+=(b.sum+num*b.num)%modd,
a.sqr+=b.sqr+(b.sum*num%modd*)+(b.num*num%modd*num%modd),
a.num-=a.num>=modd?modd:,a.sum-=a.sum>=modd?modd:,
a.sqr%=modd;
} int s[],len;
inline ll get(ll num){
if(num==)return ;
register int i,j,k,x,pre2;ll tmp,ans=,pre,pre1;zs b; for(tmp=num,len=;tmp;tmp/=)s[++len]=tmp%;
for(i=;i<len;i++)for(x=;x<=;x++)for(j=;j<;j++)for(k=;k<;k++)ans+=f[i][x][][j][k].sqr,ans-=ans>=modd?modd:;
for(x=;x<s[len];x++)for(j=;j<;j++)for(k=;k<;k++)ans+=f[len][x][][j][k].sqr,ans-=ans>=modd?modd:; pre=s[len]*ten[len-]%modd,pre1=s[len]*ten[len-]%,pre2=s[len]%;
if(s[len]!=)
for(i=len-;i;i--){
// printf(" i:%d pre1:%lld pre2:%d pre:%lld\n",i,pre1,pre2,pre);
for(x=;x<s[i];x++)for(j=;j<;j++)for(k=;k<;k++)
b=f[i][x][][(j-pre2+)%][(k-pre1+)%],
ans=(ans+b.sqr+b.sum*pre%modd*+b.num*pre%modd*pre%modd)%modd;
pre=(pre+s[i]*ten[i-])%modd;pre1=(pre1+s[i]*ten[i-])%;pre2=(pre2+s[i])%;
if(s[i]==)break;
}
return ans;
}
int main(){
register int i,j,k,j1,k1,x;ll num; for(i=ten[]=;i<=;i++)ten[i]=ten[i-]*;
for(i=;i<=;i++)k=i%,f[][i][i==][k][k]=(zs){,i,i*i};
for(i=;i<=;i++)
for(j=;j<;j++)for(k=;k<;k++)
for(x=num=;x<=;x++,num+=ten[i-]){
j1=j-x%,j1+=j1<?:,k1=k-(num%),k1+=k1<?:;
if(x!=)
for(int x1=;x1<=;x1++)add(f[i][x][][j][k],f[i-][x1][][j1][k1],num);
else
for(int x1=;x1<=;x1++)add(f[i][x][][j][k],f[i-][x1][][j1][k1],num);
for(int x1=;x1<=;x1++)add(f[i][x][][j][k],f[i-][x1][][j1][k1],num);
} int T;
for(scanf("%d",&T);T;T--){
scanf("%lld%lld",&l,&r);
printf("%lld\n",(get(r+)-get(l)+modd)%modd);
}
return ;
}

[hdu3652]B-number

  要求出区间内包含13,并且能被13整除的数的个数。

  f[i][j][k][l]表示i位数,开头为j,k表示是否包含13,l表示数字模13后的结果,的方案数

 #include<cstdio>
#include<iostream>
#include<cstring>
#define ll long long
using namespace std;
int ten[];
int f[][][][];
int i,j,k,j1,k1,n,m; int s[],len;
inline int get(int x){
if(x<)return ;
register int i,j,k,j1,k1,ans=,pre;int tmp;
for(len=,tmp=x;tmp;tmp/=)s[++len]=tmp%;
for(i=;i<len;i++)for(j=;j<=;j++)ans+=f[i][j][][];
for(i=;i<s[len];i++)ans+=f[len][i][][]; pre=(s[len]*ten[len-])%;bool flag=;
for(i=len-;i;i--){
k=(-pre+)%;
if(!flag)
for(j=;j<s[i];j++)ans+=f[i][j][][k];
else
for(j=;j<s[i];j++)ans+=f[i][j][][k]+f[i][j][][k];
if(!flag&&s[i+]==&&s[i]>)ans+=f[i][][][k];
if(s[i]==&&s[i+]==)flag=;
pre=(pre+s[i]*ten[i-])%;
}
if(flag)ans+=pre==;
return ans;
}
int main(){
for(i=ten[]=;i<=;i++)ten[i]=ten[i-]*;
for(i=;i<=;i++)f[][i][][i]=;
for(i=;i<=;i++)for(j=;j<=;j++){ for(k=;k<;k++){
for(j1=,k1=(k-j*ten[i-]%+)%;j1<=;j1++){
if(j!=||j1!=) f[i][j][][k]+=f[i-][j1][][k1];
else f[i][j][][k]+=f[i-][j1][][k1];
f[i][j][][k]+=f[i-][j1][][k1];
}
// printf(" %d %d %d %d\n",i,j,k,f[i][j][1][k]);
}
}
while(scanf("%d",&n)==)
printf("%d\n",get(n)); return ;
}

[hdu3709]Balanced Number

  无力去膜题解。http://blog.csdn.net/acm_cxlove/article/details/7821726

  顺便感受了一下记忆化搜索在处理边界等方面的优越性= =

  感觉for的话就是负数不太好处理。

 #include<cstdio>
#include<iostream>
#include<cstring>
#define ll long long
using namespace std;
int i,j,k,n,m;
int s[],len;ll tmp,l,r;
ll f[][][],ten[];
bool u[][][]; inline ll dfs(int x,int pos,int pre,bool limit){//考虑剩下的x位数字,支点已确定在pos
if(!x||pre<) return pre==;
if(!limit&&u[x][pos][pre])return f[x][pos][pre]; int mx=limit?s[x]:;ll ans=;
for(int i=;i<=mx;i++)
ans+=dfs(x-,pos,pre-i*(pos-x),limit&&(i==mx));
if(!u[x][pos][pre]&&!limit)
f[x][pos][pre]=ans,u[x][pos][pre]=;
return ans;
}
inline ll get(ll x){
ll ans=;
for(int i=;i<=;i++)
if(x==ten[i]){x--,ans++;break;}
if(x<)return ; for(len=,tmp=x;tmp;tmp/=)s[++len]=tmp%;
for(int i=len;i;i--)
ans+=dfs(len,i,,);
return ans-len+;
}
int main(){
for(i=ten[]=;i<=;i++)ten[i]=ten[i-]*;
int T;
for(scanf("%d",&T);T;T--){
scanf("%lld%lld",&l,&r);
printf("%lld\n",get(r)-get(l-));
}
return ;
}

UPD:其实以上写法中,f 数组的“以数字j开头”的那维都是不必要的。。。(所以我个傻逼预处理比别人多了两重循环TAT

几道数位DP的更多相关文章

  1. HDU2089 不要62[数位DP]

    不要62 Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submis ...

  2. 浅谈数位DP

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

  3. hdu5642 数位dp

    题目链接:http://acm.split.hdu.edu.cn/showproblem.php?pid=5642 题意:一个长度为n的序列,合法序列为字符中不能出现长度大于3的连续相等的字符,求一共 ...

  4. 动态规划晋级——HDU 3555 Bomb【数位DP详解】

    转载请注明出处:http://blog.csdn.net/a1dark 分析:初学数位DP完全搞不懂.很多时候都是自己花大量时间去找规律.记得上次网络赛有道数位DP.硬是找规律给A了.那时候完全不知数 ...

  5. Ural1057 - Amount of Degrees(数位DP)

    题目大意 求给定区间[X,Y]中满足下列条件的整数个数:这个数恰好等于K个互不相等的B的整数次幂之和.例如,设X=15,Y=20,K=2,B=2,则有且仅有下列三个数满足题意: 输入:第一行包含两个整 ...

  6. 【HDU 3652】 B-number (数位DP)

    B-number Problem Description A wqb-number, or B-number for short, is a non-negative integer whose de ...

  7. 【数位DP】【HDU2089】不要62

    不要62 Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submi ...

  8. hdoj2089(入门数位dp)

    题目链接:https://vjudge.net/problem/HDU-2089 题意:给定一段区间求出该区间中不含4且不含连续的62的数的个数. 思路:这周开始做数位dp专题,给自己加油^_^,一直 ...

  9. Luogu3220 HNOI2012 与非 数位DP

    传送门 题意:给出$N$个范围在$[0,2^k-1]$的整数,定义位运算$NAND$为位运算$AND$的逆运算,求$[L,R]$中有多少数能成为若干个前面给出的整数.若干括号和$NAND$运算组成的表 ...

随机推荐

  1. Lvs+keepAlived实现负载均衡高可用集群(DR实现)

    第1章 LVS 简介 1.1 LVS介绍 LVS是Linux Virtual Server的简写,意为Linux虚拟服务器,是虚拟的服务器集群系统,可在UNIX/LINUX平台下实现负载均衡集群功能. ...

  2. JAVA Socket编程(二)之TCP通信

    基于TCP(面向连接)的socket编程,分为客户端和服务器端. 客户端的流程如下: (1)创建套接字(socket) (2)向服务器发出连接请求(connect) (3)和服务器端进行通信(send ...

  3. linux系统下,安装centos7.0系统,配置网卡出现的问题(与centos5.x、centos6.x版本,有差异)

    1.新建虚拟机时,自己下载的是centos64系统,选择系统时,默认选择centos,而未选择centos64位,导致犯了一个低级错误,导致后面网卡安装一直有问题 2.查看ip命令与centos5.x ...

  4. Akka Cluster简介与基本环境搭建

      akka集群是高容错.去中心化.不存在单点故障以及不存在单点瓶颈的集群.它使用gossip协议通信以及具备故障自动检测功能. Gossip收敛   集群中每一个节点被其他节点监督(默认的最大数量为 ...

  5. eclipse无法识别Web项目的问题

    1.如果导入web项目后,eclipse无法将其识别为web项目,因而无法发布到tomcat容器中的话,可以采取以下步骤尝试解决: 选中项目名称并点击右键,选择“Properties”项,在出项的面板 ...

  6. js变量提升与函数提升

    在es6之前,js语言并没有块级作用域,即{}形成的作用域,只有全局作用域和函数作用域,所谓的提升,即是将该变量的声明或者函数的声明提升,举个例子 console.log(global); //und ...

  7. Nodejs进阶:crypto模块中你需要掌握的安全基础

    本文摘录自<Nodejs学习笔记>,更多章节及更新,请访问 github主页地址. 一. 文章概述 互联网时代,网络上的数据量每天都在以惊人的速度增长.同时,各类网络安全问题层出不穷.在信 ...

  8. C# 命名空间和程序集

    一.命名空间 1.通过使用using关键字引入命名空间,减少代码量 命名空间对相关的类型进行逻辑分组,通过命名空间能快速的定位到相关的类型,例如:在System.IO命名空间下,定义了所有I/O操作的 ...

  9. Java 反编译工具下载

    反编译,通俗来讲,就是将.java 文件经过编译生成的 .class 文件还原.注意这里的还原不等于 .java 文件.因为Java编译器在编译.java 文件的时候,会对代码进行一些处理. 那么接下 ...

  10. H2Engine游戏服务器设计之属性管理器

    游戏服务器设计之属性管理器 游戏中角色拥有的属性值很多,运营多年的游戏,往往会有很多个成长线,每个属性都有可能被N个成长线模块增减数值.举例当角色戴上武器时候hp+100点,卸下武器时HP-100点, ...