记忆化搜索的专题

题解在代码中

Amount of Degrees[loj 10163]

/*
此题可以转换成将10进制转成b进制后有k个1其他都为0的个数
所以用记忆化dfs
dp[pos][sum]表示将要处理第pos位,前面已有sum个一的数量
*/
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
inline long long read()
{
long long f=,ans=;char c;
while(c<''||c>''){if(c=='-')f=-;c=getchar();}
while(c>=''&&c<=''){ans=ans*+c-'';c=getchar();}
return ans*f;
}
int x,y,k,b,dg[],ans,dp[][];
long long dfs(long long pos,long long sum,long long done,long long sry)
{
// cout<<"位置:"<<pos<<" 一的个数:"<<sum<<" 小于等于:"<<done<<" 原来的数:"<<sry<<endl;
if(sum>k) return ;
if(pos==)
{
if(sum==k) return ;
return ;
}
if(done==&&dp[pos][sum]!=-) return dp[pos][sum];
long long end;
if(done==) end=;
else end=min(,dg[pos]);
long long maxn=;
for(long long i=;i<=end;i++)
{
if(i==) maxn+=dfs(pos-,sum+,done&&i==dg[pos],i);
else maxn+=dfs(pos-,sum,done&&i==dg[pos],i);
}
if(done==) dp[pos][sum]=maxn;
return maxn;
}
long long solve(long long x)
{
ans=;memset(dg,,sizeof(dg));
while(x!=)
{
dg[++ans]=x%b;
x/=b;
}
// for(long long i=ans;i>=1;i--) cout<<dg[i]<<" ";
// cout<<endl;
return dfs(ans,,,<<-);
}
int main()
{
memset(dp,-,sizeof(dp));
x=read(),y=read(),k=read(),b=read();
cout<<solve(y)-solve(x-);
}

数字游戏[loj 10164]

/*
记忆化dfs
dp[pos][sta]表示将要处理第pos位,上一位是sta的数量
*/
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cmath>
using namespace std;
inline int read()
{
int f=,ans=;char c;
while(c<''||c>''){if(c=='-')f=-;c=getchar();}
while(c>=''&&c<=''){ans=ans*+c-'';c=getchar();}
return f*ans;
}
int dp[][],ans,dg[];
int dfs(int pos,int sta,int done)//done为是否与原数小于或相等
{
// cout<<pos<<" "<<sta<<" "<<done<<endl;
if(pos==) return ;
if(done==&&dp[pos][sta]!=-) return dp[pos][sta];
int end;
if(done==) end=;
else end=dg[pos];
// cout<<end<<endl;
int maxn=;
for(int i=sta;i<=end;i++)
maxn+=dfs(pos-,i,done&&i==dg[pos]);
if(done==) dp[pos][sta]=maxn;
return maxn;
}
int solve(int x)
{
ans=;
while(x!=)
{
dg[++ans]=x%;
x/=;
}
// cout<<ans<<endl;
// for(int i=ans;i>=1;i--) cout<<dg[i]<<" ";cout<<endl;
return dfs(ans,,);
}
int main()
{
memset(dp,-,sizeof(dp));
int a,b;
while(scanf("%d%d",&a,&b)!=EOF)
{
printf("%d\n",solve(b)-solve(a-));
// return 0;
}
return ;
}
/*
1 20
*/

Windy 数[loj 10165]

/*
注意前导0,将它转换成11即可,想一想为什么
dp[pos][sta],记忆化dfs
当前位数,上次的数字
*/
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cmath>
using namespace std;
inline long long read()
{
long long f=,ans=;char c;
while(c<''||c>''){if(c=='-')f=-;c=getchar();}
while(c>=''&&c<=''){ans=ans*+c-'';c=getchar();}
return f*ans;
}
long long dp[][];
long long dg[];
long long dfs(long long pos,long long sta,long long done)//若flag为0,没有出现真正位
{
// cout<<"位数:"<<pos<<" 所得位数:"<<sta<<" 与原数的大小:"<<done<<" 有没有真正的位"<<flag<<endl;
if(pos==) return ;
if(done==&&dp[pos][sta]!=-) return dp[pos][sta];
long long end;
if(done==) end=dg[pos];
else end=;
long long maxn=;
// dfs(ans,0,1,0)
//long long dfs(long long pos,long long sta,long long done,bool flag)//若flag为0,没有出现真正位
for(long long i=;i<=end;i++)
{
if(abs(i-sta)<) continue;
if(sta==&&i==) maxn+=dfs(pos-,,done&&i==end);
else maxn+=dfs(pos-,i,done&&i==dg[pos]);
}
if(done==) dp[pos][sta]=maxn;
return maxn;
}
long long solve(long long x)
{
memset(dg,,sizeof(dg));
long long ans=;
while(x!=)
{
dg[++ans]=x%;
x/=;
}
// for(long long i=ans;i>=1;i--) cout<<dg[i]<<" ";cout<<endl;
return dfs(ans,,);
}
int main()
{
memset(dp,-,sizeof(dp));
long long a=read(),b=read();
cout<<solve(b)-solve(a-);
int x;
// while(scanf("%d",&x)!=EOF) cout<<solve(x)<<endl;
// long long x=read();cout<<solve(x);
return ;
}

数字游戏[loj 10166]

/*
sum为mod n的和
记忆化dfs,dp[pos][sum],不解释
*/
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cmath>
using namespace std;
inline long long read()
{
long long f=,ans=;char c;
while(c<''||c>''){if(c=='-')f=-;c=getchar();}
while(c>=''&&c<=''){ans=ans*+c-'';c=getchar();}
return f*ans;
}
long long a,b,dg[],dp[][],mod;
long long dfs(long long pos,long long sta,long long done,long long sum)
{
// cout<<"位数:"<<pos<<" 此数:"<<sta<<" 是否小于等于:"<<done<<" 和:"<<sum<<endl;
if(pos==)
{
if(sum%mod==) return ;
else return ;
}
if(done==&&dp[pos][sum]!=-) return dp[pos][sum];
long long end;
if(done==) end=;
else if(done==) end=dg[pos];
long long maxn=;
for(long long i=;i<=end;i++)
{
maxn+=dfs(pos-,i,done&&i==dg[pos],(sum+i)%mod);
}
if(done==) dp[pos][sum]=maxn;
return maxn;
}
long long solve(long long x)
{
memset(dg,,sizeof(dg));
long long ans=;
while(x!=)
{
dg[++ans]=x%;
x/=;
}
return dfs(ans,,,);
}
int main()
{ while(cin>>a>>b>>mod)
{
memset(dp,-,sizeof(dp));
cout<<solve(b)-solve(a-)<<endl;
}
// a=read(),b=read(),mod=read(); }
/*
19 9
*/

不要 62[loj 10167]

/*
只要不让62,4进for循环即可
dp[pos][sta]
*/
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cmath>
using namespace std;
inline int read()
{
int f=,ans=;char c;
while(c<''||c>''){if(c=='-')f=-;c=getchar();}
while(c>=''&&c<=''){ans=ans*+c-'';c=getchar();}
return f*ans;
}
int dg[],dp[][];
int dfs(int pos,int sta,int done,bool flag)
{
// cout<<pos<<" "<<sta<<" "<<done<<" "<<flag<<endl;
if(pos==) return ;
if(done==&&dp[pos][sta]!=-) return dp[pos][sta];
int end;
if(done==) end=;
if(done==) end=dg[pos];
int maxn=;
for(int i=;i<=end;i++)
{
if(i==) continue;
if(i==&&flag==true) continue;
if(i==) maxn+=dfs(pos-,i,done&&i==dg[pos],true);
else maxn+=dfs(pos-,i,done&&i==dg[pos],false);
}
if(done==) dp[pos][sta]=maxn;
return maxn;
}
int solve(int x)
{
memset(dg,,sizeof(dg));
int ans=;
while(x!=)
{
dg[++ans]=x%;
x/=;
}
// for(int i=ans;i>=1;i--) cout<<dg[i]<<" ";
// cout<<endl;
return dfs(ans,,,false);
}
int main()
{
memset(dp,-,sizeof(dp));
// int x=read();
// cout<<solve(x)<<endl;return 0;
while()
{
int a=read(),b=read();
if(a==&&b==) return ;
cout<<solve(b)-solve(a-)<<endl;
}
}

恨 7 不成妻[loj 10168]

/*
主要是求平方和,其他的都可以记忆化搜索实现
dp[pos][pre1][pre2]表示当前以pos位作为下一位,pre1记录数字和,pre2记录数字
(i+next)^2=i*i+2*i*next+next*next
而放眼望去,合并同类项后可的
(i+next)^2=i*i+2*i*(接下来的数字和)+(平方和)
所以搜索把每一个都记录下来即可
*/
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
const long long mod=;
using namespace std;
inline long long read()
{
long long f=,ans=;char c;
while(c<''||c>''){if(c=='-')f=-;c=getchar();}
while(c>=''&&c<=''){ans=ans*+c-'';c=getchar();}
return ans*f;
}
struct node{
long long cnt;//个数
long long sum;//和
long long sqsum;//平方和
}dp[][][];
long long p[];
long long dg[];
node dfs(long long pos,long long pre1,long long pre2,long long done)//pre1表示数字和,pre2表示数字
{
if(pos==-)
{
node tmp;
tmp.cnt=tmp.sqsum=tmp.sum=;
if(pre1!=&&pre2!=) tmp.cnt=;
return tmp;
}
if(done== && dp[pos][pre1][pre2].cnt!=-) return dp[pos][pre1][pre2];
long long end;
if(done==) end=;
if(done==) end=dg[pos];
node ans;
ans.cnt=ans.sqsum=ans.sum=;
for(long long i=;i<=end;i++)
{
if(i==) continue;
node tmp=dfs(pos-,(pre1+i)%,(pre2*+i)%,done&&i==dg[pos]);
ans.cnt+=tmp.cnt;
ans.cnt%=mod;
ans.sum+=(tmp.sum+((p[pos]*i%mod)%mod)*tmp.cnt%mod)%mod;
ans.sum%=mod;
ans.sqsum+=(tmp.sqsum+((*p[pos]%mod*i)%mod)*tmp.sum)%mod;
ans.sqsum%=mod; ans.sqsum+=((p[pos]%mod*p[pos]%mod)*(tmp.cnt)%mod*(i%mod*i%mod)%mod);
ans.sqsum%=mod;
}
if(done==) dp[pos][pre1][pre2]=ans;
return ans; }
long long solve(long long x)
{
long long anss=;
while(x!=)
{
dg[anss++]=x%;
x/=;
}
return dfs(anss-,,,).sqsum;
}
int main()
{
p[]=;
for(int i=;i<;i++)
p[i]=(p[i-]*)%mod;
for(int i=;i<;i++)
for(int j=;j<;j++)
for(int k=;k<;k++)
dp[i][j][k].cnt=-;
long long t=read(),l,r;
while(t--)
{
l=read();r=read();
printf("%d\n",(solve(r)-solve(l-)+mod)%mod);
}
}
/*
1
2065 7880
*/

数字计数[loj 10169]

/*
其实感觉跟例题1没有什么区别
只要再看看前导0即可
*/
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
inline long long read()
{
long long f=,ans=;char c;
while(c<''||c>''){if(c=='-')f=-;c=getchar();}
while(c>=''&&c<=''){ans=ans*+c-'';c=getchar();}
return ans*f;
}
long long a,b,cur,dg[],dp[][];
long long dfs(long long pos,long long done ,long long zero,long long sum)
{
if(pos==) return sum;
if(done==&&zero==&&dp[pos][sum]!=-) return dp[pos][sum];
long long end;
if(done==) end=dg[pos];
else end=;
long long maxn=;
for(long long i=;i<=end;i++)
maxn+=dfs(pos-,done&&i==dg[pos],zero&&i==,sum+(cur==&&i==&&zero==||cur&&i==cur));
if(done==&&zero==) dp[pos][sum]=maxn;
return maxn;
}
long long solve(long long x)
{
memset(dp,-,sizeof(dp));
long long ans=;
while(x!=)
{
dg[++ans]=x%;
x/=;
}
return dfs(ans,,,);
}
int main()
{
a=read(),b=read();
for(cur=;cur<=;cur++)
cout<<solve(b)-solve(a-)<<" ";
}

YBT 5.3 数位动态规划的更多相关文章

  1. YBT 5.2 树形动态规划

    题解在代码中 二叉苹果树[loj 10153] /* 若要留q条边便是要留q+1个点 所以记忆化搜索 dp[pos][ans]=max(dp[pos][ans],dp[l[pos]][k]+dp[r[ ...

  2. [题解+总结]动态规划大合集II

    1.前言 大合集总共14道题,出自江哥之手(这就没什么好戏了),做得让人花枝乱颤.虽说大部分是NOIP难度,也有简单的几道题目,但是还是做的很辛苦,有几道题几乎没思路,下面一道道边看边分析一下. 2. ...

  3. 数位dp 的简单入门

    时间紧张,就不讲那么详细了. 之前一直被深搜代码误解,以为数位dp 其实就是记忆化深搜...(虽说爆搜确实很舒服而且还好想) 但是后来发现数位dp 的标准格式其实是 预处理 + dp ...... 数 ...

  4. 『嗨威说』算法设计与分析 - 动态规划思想小结(HDU 4283 You Are the One)

    本文索引目录: 一.动态规划的基本思想 二.数字三角形.最大子段和(PTA)递归方程 三.一道区间动态规划题点拨升华动态规划思想 四.结对编程情况 一.动态规划的基本思想: 1.1 基本概念: 动态规 ...

  5. 动态规划大合集II

    1.前言 大合集总共14道题,出自江哥之手(这就没什么好戏了),做得让人花枝乱颤.虽说大部分是NOIP难度,也有简单的几道题目,但是还是做的很辛苦,有几道题几乎没思路,下面一道道边看边分析一下. 2. ...

  6. OI省选算法汇总

    copy from hzwer @http://hzwer.com/1234.html 侵删 1.1 基本数据结构 1. 数组 2. 链表,双向链表 3. 队列,单调队列,双端队列 4. 栈,单调栈 ...

  7. hdu_3555 bomb

    数位动态规划     数位动态规划是求解一个大区间[L, R]中间满足条件Q的所有数字的个数(或者和,或其他)的一种方法.它通过分析每一位上的数字,一般用 dp[len][digit][...] 来表 ...

  8. hdu_2089 不要62

    数位动态规划     数位动态规划是求解一个大区间[L, R]中间满足条件Q的所有数字的个数(或者和,或其他)的一种方法.它通过分析每一位上的数字,一般用 dp[len][digit][...] 来表 ...

  9. Careercup - Google面试题 - 4857362737266688

    2014-05-04 00:10 题目链接 原题: Write a function return an integer that satisfies the following conditions ...

随机推荐

  1. SQL Sever查询语句集锦

    一. 简单查询简单的Transact-SQL查询只包括选择列表.FROM子句和WHERE子句.它们分别说明所查询列.查询的表或视图.以及搜索条件等. 例如,下面的语句查询testtable表中姓名为“ ...

  2. Oracle存储过程练习题

    1.1.创建一个过程,能向dept表中添加一个新记录.(in参数) 创建过程 create or replace procedure insert_dept ( num_dept in number, ...

  3. TW实习日记:第29-30天

    这两天挺忙,赶工期,改bug.项目现场的同事说客户火大得不行.可是谁叫你们谈工期谈的这么紧,完全不考虑开发的情况,真的是烦人这种事情.这两天遇到的最有难度的一个点就是附件预览,搞这个改到晚上11点. ...

  4. lintcode: Check Sum of Square Numbers

    Check Sum of Square Numbers Given a integer c, your task is to decide whether there're two integers ...

  5. 78[LeetCode] Subsets

    Given a set of distinct integers, nums, return all possible subsets (the power set). Note: The solut ...

  6. [LeetCode] 53. Maximum Subarray 解题思路

    Find the contiguous subarray within an array (containing at least one number) which has the largest ...

  7. nodejs笔记--与Redis的交互篇(六)

    原文地址:http://www.cnblogs.com/zhongweiv/p/node_redis.html 安装前准备 win64: Install python: http://www.pyth ...

  8. 使用HTML5制作loading图

    昨天发了一篇使用HTML5 canvas写的时钟的文章,今天发一篇关于使用HTML5制作loading图的文章. <!DOCTYPE html> <html> <head ...

  9. 词频统计 SPEC 20170914 1 1 1 1 1

    功能1 小文件输入,为表明程序能跑,结果真实而不是迫害老五,请他亲自键盘在控制台下输入命令. #include<stdio.h> #include<string.h> #inc ...

  10. Java容器之Set接口

    Set 接口: 1. Set 接口是 Collection 的子接口,Set 接口没有提供额外的方法,但实现 Set 接口的容器类中的元素是没有顺序的,且不可以重复: 2. Set 容器可以与数学中的 ...