题解【 [USACO4.3]逢低吸纳Buy Low, Buy Lower】
Description
给定一段时间内股票的每日售价 , 售价为正 $16$ 位整数。
每次你选择购买时,当前的股票价格必须严格低于你之前购买股票时的价格。
编写一个程序,确定你应该在哪些天购进股票,可以使得你能够购买股票的次数最大化。
数据范围 : $1≤N≤5000$ 。
例如,下面是一个股票价格时间表:
Day 1 2 3 4 5 6 7 8 9 10 11 12 Price 68 69 54 64 68 64 70 67 78 62 98 87
如果每次购买都必须遵循当前股票价格严格低于之前购买股票时的价格,那么投资者最多可以购买四次该股票。
买进方案之一为:
Day 2 5 6 10 Price 69 68 64 62
Solution
① 朴素方法求最长下降子序列。
② 记忆化搜索求出总的不同路径。
关键:搜索要从后往前搜索,因为从前往后搜索会遗漏一些情况。
例如 :
100 90 80 70 60 71 60
如果用从前往后搜索,因为可以认为在相同长度且当前数字相同时的路径会重复,我们会排除掉同样长度且当前位置数字相同的数,dp 数组中存储的是第五个 $60$ 开始的路径总数,到第七个 $60$ 时会略过,而显然,第七个 $60$ 有一条路径 $100, 90 , 80 , 71 , 60$ 是第五个 $60$ 搜索不到的。
代码
高精没用,90 分代码如下,个人认为高精不是这道题的精华。
#include<bits/stdc++.h>
using namespace std;
long long a[5005],f1[5005],f2[5005],n,ans=0,res=0,r[5005],cou=0;
long long dfs(int t) {
long long temp=0;
if(f1[t]==1){
return 1;
}
if(f2[t]!=-1){
return f2[t];
}
long long oo[5005],cc=0;
for(int i=t-1;i>=1;i--) {
if(a[i]>a[t]&&f1[t]==f1[i]+1){
bool flag=1;
for(int j=1;j<=cc;j++) {
if (a[i]==oo[j]) {
flag=0;
break;
}
}
if(flag==1){
oo[++cc]=a[i];
temp+=dfs(i);
}
}
}
return f2[t]=temp;
}
int main(){
scanf("%lld",&n);
for(int i=1;i<=n;i++){
scanf("%lld",&a[i]);
}
for(int i=1;i<=n;i++){
f1[i]=1;
for(int j=1;j<i;j++){
if(a[i]<a[j]){
f1[i]=max(f1[i],f1[j]+1);
}
}
}
for(int i=1;i<=n;i++){
ans=max(ans,f1[i]);
}
memset(f2,-1,sizeof(f2));
for (int i=n;i>=1;i--){
if(ans==f1[i]){
int pd=1;
for(int j=1;j<=cou;j++) {
if(a[i]==r[j]){
pd=0;
break;
}
}
if (pd==1) {
r[++cou]=a[i];
res+=dfs(i);
}
}
}
printf("%lld %lld",ans,res);
return 0;
}

浙公网安备 33010602011771号