几道数位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$运算组成的表 ...
随机推荐
- 【USACO】玉米实验(单调队列)
Description 约翰决定培育新的玉米品种以提高奶牛的产奶效率.约翰所有的土地被分成 N ×N 块,其中第 r行第 c 列的玉米质量为 Ar,c.他打算找一块质量比较均匀的土地开始自己的实验.经 ...
- mouseout、mouseover和mouseleave、mouseenter区别
今天在使用鼠标事件时,用错了mouseout,于是做个测试总结. 结论: mouseenter:当鼠标移入某元素时触发. mouseleave:当鼠标移出某元素时触发. mouseover:当鼠标移入 ...
- ES6/7 异步编程学习笔记
前言 在ES6的异步函数出现之前,Js实现异步编程只有settimeout.事件监听.回调函数等几种方法 settTmeout 这种方法常用于定时器与动画的功能,因为其本质上其实是浏览器的WebAPI ...
- ArcGIS API for JavaScript 4.2学习笔记[18] 搜索小部件
这个例子很简单,作为开学后(暴露出学生党的本质)的开胃菜是再合适不过了. 不过,博主提前警告一下:接下来的例子会相当的长.烦.难.我还会用"引用"-"函数参数骨架&quo ...
- gitlab 本地 定时备份
=============================================== 20171015_第1次修改 ccb_warlock === ...
- 让你彻底弄清offset
很多初学者对于JavaScript中的offset.scroll.client一直弄不明白,虽然网上到处都可以看一张图(图1),但这张图太多太杂,并且由于浏览器差异性,图示也不完全正确. 图一 不知道 ...
- python中顺序查找分析和实现
顺序查找算法是一种很基本的查找算法,该算法的复杂度一般是最大是O(n),假如加上顺序查找,算法的复杂度 还要降一倍,为O(n/2). Python的代码实现如下所示: def sequential_s ...
- c3p0使用记录
首先要导入c3p0包.c3p0下载解压后,lib目录下有三个包,使用mysql的话,只需要导入c3p0-0.9.5.2.jar,mchange-commons-java-0.2.11.jar. 要连接 ...
- Swift3中数组创建方法
转载自:http://blog.csdn.net/bwf_erg/article/details/70858865 数组是由一组类型相同的元素构成的有序数据集合.数组中的集合元素是有 序的,而且可以重 ...
- 浅谈JavaScript的面向对象程序设计(二)
前面介绍通过Object构造函数或者字面量创建单个对象,但是通过这个的方法创建对象有明显的缺点:调用同一个接口创建多个实例,会产生大量的重复代码.怎么样解决? 工厂模式 工厂模式是软件工程领域经常使用 ...