记忆化搜索的专题

题解在代码中

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. jmeter "you cannot switch bacause data cannot be converted to target Tab data,empty data to switch"报错

    jmeter "you cannot switch bacause data cannot be converted to target Tab data,empty data to swi ...

  2. python程序设计——面向对象程序设计:类

    理解面向对象 基本原则是,计算机程序由多个能够起到子程序作用的单元或对象组合而成 关键性观念是,数据以及对数据的操作封装在一起,组成一个相互依存.不可分割的整体,即对象 python面向对象特性 完全 ...

  3. python3对接聊天机器人API

    详情见http://api.qingyunke.com/智能机器人API接口说明支持功能:天气.翻译.藏头诗.笑话.歌词.计算.域名信息/备案/收录查询.IP查询.手机号码归属.人工智能聊天接口地址: ...

  4. vscode开发智能合约

    开发工具 EOS 开发终极神器-vscode (你绝对找不到的干货) lome · 2018年04月19日 · 最后由 18636292520 回复于 2018年09月15日 · 15672 次阅读 ...

  5. HDU 4169 Wealthy Family(树形DP)

    Problem Description While studying the history of royal families, you want to know how wealthy each ...

  6. Thunder团队第二周 - Scrum会议5

    Scrum会议5 小组名称:Thunder 项目名称:爱阅app Scrum Master:苗威 工作照片: 参会成员: 王航:http://www.cnblogs.com/wangh013/ 李传康 ...

  7. 20162328蔡文琛week01

    学号20162328 <程序设计与数据结构>第1周学习总结 教材学习内容总结 通过练习课本上给出的代码并结合老师所提供教程,熟悉并初步了解Java的基本编辑 教材学习中的问题和解决过程 无 ...

  8. Java 抽象类和Final关键字

    抽象类 用abstract关键字来修饰一个类时,这个类叫抽象类: 用abstract关键字来修饰一个方法时,该方法叫做抽象方法. 含有抽象方法的类必须被定义而为抽象类,抽象类必须被继承,抽象方法必须被 ...

  9. 分页查询es时,返回的数据不是自己所期望的问题

    在进行es分页查询时,一般都是用sql语句转成es查询字符串,在项目中遇到过不少次返回的数据不是自己所期望的那样时,多半原因是自己的sql拼接的有问题. 解决办法:务必要保证自己的sql语句拼接正确.

  10. Debian 7 amd64--TP-LINK TL-WN725N 2.0源码驱动编译安装

    租房用的是无线网络,在新安装的Debian 7 amd64使用的无线网卡型号是TP-LINK TL-WN725N 2.0,发现驱动安装还是有些问题,折腾了很久,特意在此记录一下. TL-WN725N ...