在复习动态规划时发现了几道有趣的题,与大家分享一下!
目录
题目一
题目描述
奶牛们开始了新的生意,它们的主人约翰想知道它们到底能做得多好。这笔生意已经做了N(1≤N≤100,000)天,每天奶牛们都会记录下这一天的利润Pi(-1,000≤Pi≤1,000)。
约翰想要找到奶牛们在连续的时间期间所获得的最大的总利润。(注:连续时间的周期长度范围从第一天到第N天)。
请你写一个计算最大利润的程序来帮助他。
输入输出样例
输入 #1
7 -3 4 9 -2 -5 8 -3
输出 #1
14
分析题意
这是一道最大连续子序列(子串),还是一道标准例题,掌握动态转移方程就可以解出来了。
方程如下:
if(b[i-1]>0){
b[i]=b[i]+b[i-1];
}
判断是否大于零,否则没必要去记录下来(最大)。
代码就呈现给大家:
#include<bits/stdc++.h>
using namespace std;
int a,b[100005],ans=-0x3f3f3f3f3f3f;
int main(){
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin>>a;
for(int i=1;i<=a;i++){
cin>>b[i];
}
for(int i=1;i<=a;i++){
if(b[i-1]>0){
b[i]=b[i]+b[i-1];
}
}
for(int i=1;i<=a;i++){
if(b[i]>ans){
ans=b[i];
}
}
cout<<ans;
}
注意:整个数列也可以都是负数,所以记录数组ans要开的很小!
题目二
题目描述
FJ 到商场买工具。商场里有 K 种工具(1≤K≤100),价格分别为 1,2,…,K 元。FJ 手里有 N 元( 1≤N≤1000),必须花完。他有多少种购买方案呢?
输入格式
一行两个整数 N,K。
输出格式
输出不同的购买方案数。
输入输出样例
输入 #1
5 3
输出 #1
5
分析题意
这是标准的背包问题(2),无穷版的背包问题,来尝试一下!
核心代码:
for(int i=1;i<=a;i++){
for(int j=i;j<=b;j++){
f[j]+=f[j-i];
}
}
将现在状态与上一个状态加起来,就是结果。
代码如下:
#include<bits/stdc++.h>
using namespace std;
long long a,b,c,ans=0,Max;
long long f[100005];
int main(){
cin>>b>>a;
f[0]=1;
for(int i=1;i<=a;i++){
for(int j=i;j<=b;j++){
f[j]+=f[j-i];
}
}
cout<<f[b];
return 0;
}
可是就只有70分
看了看优秀的题解
发现要用一些技巧(要用__int128):
__int128 f[10001];
void write(__int128 x){
if(x>9) write(x/10);
putchar(x%10+'0');
}
这样就能AC了!
代码:
#include<bits/stdc++.h>
using namespace std;
long long a,b,c,ans=0,Max;
__int128 f[10001];
void write(__int128 x){
if(x>9) write(x/10);
putchar(x%10+'0');
}
int main(){
cin>>b>>a;
f[0]=1;
for(int i=1;i<=a;i++){
for(int j=i;j<=b;j++){
f[j]+=f[j-i];
}
}
write(f[b]);
return 0;
}
课后习题:
总结
dp看起来不难,但要发现动态转移方程要有良好的思维,还要进行大量的验证,最后抓住要点就可以啦!
注释
冷知识:int 大小受电脑字长影响,早期电脑通常为16位,那么 int最大值 为:2^(16-1)-1;好一点的电脑为32位,那么 int最大值 为:2^(32-1)-1。
现在最差的电脑也有32位,一般为64位,绝大多数情况默认64位。
即目前 int最大值 皆为2^(32-1)-1,不会更大。
long long 最大值:2^(64-1)-1【不可改变】
__int128 大小:2^(128-1)-1 【不可改变】
经作者实测,这样
__int128
的精确范围是:
−170141183460469231731687303715884105728−170141183460469231731687303715884105728 ~ 170141183460469231731687303715884105727