P1108 低价购买
Problem
“低价购买”这条建议是在奶牛股票市场取得成功的一半规则。要想被认为是伟大的投资者,你必须遵循以下的问题建议:“低价购买;再低价购买”。每次你购买一支股票,你必须用低于你上次购买它的价格购买它。买的次数越多越好!你的目标是在遵循以上建议的前提下,求你最多能购买股票的次数。你将被给出一段时间内一支股票每天的出售价,你可以选择在哪些天购买这支股票。每次购买都必须遵循“低价购买;再低价购买”的原则。写一个程序计算最大购买次数。
这里是某支股票的价格清单:
最优秀的投资者可以购买最多 \(4\) 次股票,可行方案中的一种是:
输入格式
第一行共一个整数 \(N\ (1 \le N \le 5000)\),股票发行天数
第二行一行 \(N\) 个整数,是每天的股票价格。保证是大小不超过 \(2^{16}\) 的正整数。
输出格式
输出共一行两个整数,分别为最大购买次数和拥有最大购买次数的方案数(数据保证 $ \le 2^{31}$)当二种方案“看起来一样”时(就是说它们构成的价格队列一样的时候),这 \(2\) 种方案被认为是相同的。
Solve
第一问
就是最长不下降子序列的翻版,求只下降的即可
第二问
设\(g_i\)为有多少种方案能实现\(f_i\)
如果不排除相同的方案,也就是说只要选择天数不严格相同即可,那么能造成第i天的最优结果方案数就是能转移给第i天的方案数之和
也就是说,算完f[i]后,只要有\(j<i且a_j>a_i且f_j+1=f_i\)
那么\(g_i=\sum g_j\)
回到题目,容易发现,如果\(a_i\neq a_j\),那么\(g_i\)和\(g_j\)就不会有重复的方案
那\(a_i=a_j\)呢?
非常简单,如果\(i>j\),那么\(g_j\)的方案都会在\(g_i\)中出现,把前者清空即可
最后可以推到n+1,这样答案可以自动汇总,但是记得第一问要减一
时间复杂度\(O(n^2)\),感觉RAM放到512MB可以降维,不知道对不对
Code
#include<bits/stdc++.h>
using namespace std;
int n,a[5005],f[5005],g[5005];
int main(){
cin>>n;
for(int i=1;i<=n;i++){
cin>>a[i];
f[i]=1;
}
for(int i=1;i<=n+1;i++){
for(int j=1;j<i;j++){
if(a[i]<a[j])f[i]=max(f[i],f[j]+1);
}
for(int j=1;j<i;j++){
if(a[j]==a[i]&&f[i]==f[j])g[j]=0;
}
for(int j=1;j<i;j++){
if(a[i]<a[j]&&f[j]+1==f[i])g[i]+=g[j];
}
g[i]=max(1,g[i]);
}
cout<<f[n+1]-1<<" "<<g[n+1];
return 0;
}

浙公网安备 33010602011771号