几道数位DP
因为这几天写的几道数位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的更多相关文章
- HDU2089 不要62[数位DP]
不要62 Time Limit: 1000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submis ...
- 浅谈数位DP
在了解数位dp之前,先来看一个问题: 例1.求a~b中不包含49的数的个数. 0 < a.b < 2*10^9 注意到n的数据范围非常大,暴力求解是不可能的,考虑dp,如果直接记录下数字, ...
- hdu5642 数位dp
题目链接:http://acm.split.hdu.edu.cn/showproblem.php?pid=5642 题意:一个长度为n的序列,合法序列为字符中不能出现长度大于3的连续相等的字符,求一共 ...
- 动态规划晋级——HDU 3555 Bomb【数位DP详解】
转载请注明出处:http://blog.csdn.net/a1dark 分析:初学数位DP完全搞不懂.很多时候都是自己花大量时间去找规律.记得上次网络赛有道数位DP.硬是找规律给A了.那时候完全不知数 ...
- Ural1057 - Amount of Degrees(数位DP)
题目大意 求给定区间[X,Y]中满足下列条件的整数个数:这个数恰好等于K个互不相等的B的整数次幂之和.例如,设X=15,Y=20,K=2,B=2,则有且仅有下列三个数满足题意: 输入:第一行包含两个整 ...
- 【HDU 3652】 B-number (数位DP)
B-number Problem Description A wqb-number, or B-number for short, is a non-negative integer whose de ...
- 【数位DP】【HDU2089】不要62
不要62 Time Limit: 1000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Total Submi ...
- hdoj2089(入门数位dp)
题目链接:https://vjudge.net/problem/HDU-2089 题意:给定一段区间求出该区间中不含4且不含连续的62的数的个数. 思路:这周开始做数位dp专题,给自己加油^_^,一直 ...
- Luogu3220 HNOI2012 与非 数位DP
传送门 题意:给出$N$个范围在$[0,2^k-1]$的整数,定义位运算$NAND$为位运算$AND$的逆运算,求$[L,R]$中有多少数能成为若干个前面给出的整数.若干括号和$NAND$运算组成的表 ...
随机推荐
- 动态WebApi
动态WebApi实现了直接对Service的调用,其实没有跨过ApiController,只是我们自己创建出ApiController 实现主要分以下几步 一 对默认WebApi服务的替换 ApiGl ...
- C:数据结构与算法之顺序表
顺序表作为数据结构的开端,说明这里面很多基础要学,初学者一开始都会混淆,今天我们来一步一步来建立一个完整的顺序表,可以任我们控制的顺序表,首先先定义一个顺序表 /* Note:Your choice ...
- HTML篇(下·)
13.Label的作用是什么?是怎么用的? label标签来定义表单控制间的关系,当用户选择该标签时,浏览器会自动将焦点转到和标签相关的表单事件上. <label for="Name& ...
- myecplise自带的tomcat问题
今天做一个项目时候,发现myecplise自带的tomcat上面部署了是可以运行的,可是当部署到自己下载的tomcat时候,就报错,tomcat可以启动,项目无法启动,查了问题,发现是web,xml中 ...
- Java8函数之旅 (八) - 组合式异步编程
前言 随着多核处理器的出现,如何轻松高效的进行异步编程变得愈发重要,我们看看在java8之前,使用java语言完成异步编程有哪些方案. JAVA8之前的异步编程 继承Thead类,重写run方法 实现 ...
- bzoj 3718: [PA2014]Parking
Description 你的老板命令你将停车场里的车移动成他想要的样子. 停车场是一个长条矩形,宽度为w.我们以其左下角顶点为原点,坐标轴平行于矩形的边,建立直角坐标系.停车场很长,我们可以认为它一直 ...
- 虚拟机创建流程中neutron代码分析(三)
前言: 当neutron-server创建了port信息,将port信息写入数据库中.流程返回到nova服务端,接着nova创建的流程继续走.在计算节点中neutron-agent同样要完成很多的工作 ...
- 自己动手写把”锁”之---JMM和volatile
一.JAVA内存模型 关于Java内存模型的文章,网上真的数不胜数.在这里我就不打算说的很详细.很严谨了.只力求大家能更好的理解和运用,为后边的技术点做铺垫. 内存模型并不是Java独有的概念,而 ...
- 设计模式之 - 策略模式(Strategy Pattern)
引入:项目中涉及到工作流,当然这个工作流的实现是由用户根据不同的策略或者说方式传入处理这个事件的人的审批链,后台在存储过程中进行解析,然后生成最终的审批链,在系统中流转进行审批. 比如审批链: 张三 ...
- Automata
A deterministic finite automaton is represented formally by a 5-tuple (Q,Σ,δ,q0,F), where: Q is a fi ...