题目
给定一段时间内股票的每日售价(正16位整数)。
你可以选择在任何一天购买股票。
每次你选择购买时,当前的股票价格必须严格低于你之前购买股票时的价格。
编写一个程序,确定你应该在哪些天购进股票,可以使得你能够购买股票的次数最大化。
例如,下面是一个股票价格时间表:
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
输入格式
第1行包含整数 N,表示给出的股票价格的天数。
第2至最后一行,共包含 N 个整数,每行10个,最后一行可能不够10个,表示 N 天的股票价格。
同一行数之间用空格隔开。
输出格式
输出占一行,包含两个整数,分别表示最大买进股票次数以及可以达到最大买进次数的方案数。
扫描二维码关注公众号,回复:
11445928 查看本文章
如果两种方案的买入日序列不同,但是价格序列相同,则认为这是相同的方案(只计算一次)。
样例
样例1输入
12
68 69 54 64 68 64 70 67 78 62 98 87
样例1输出
4 2
样例2输入
5
4 3 2 1 1
样例2输出
4 1
数据范围与提示
分析
其实我觉得这道题还是有难度的。
第一问就是LIS板子。
第二问:定义
为在保证最大结果的情况下以
为结尾的
方案总数。跑完一遍LIS后,如果
且
,说明
是由
得来的,那么
。
另外此题还有一个难点:去重。我们可以这样分析:如果 且 说明 与 的情况完全相同,这是我们就可以把 赋值为0,从而达到去重的效果。
代码
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <climits>
#include <cstring>
using namespace std;
const int MAXN = 5005;
int a[MAXN], dp[MAXN], num[MAXN];
int main() {
int n, max_ = 1, sum = 0;
scanf("%d", &n);
for(int i = 1; i <= n; i ++) {
scanf("%d", &a[i]);
}
for(int i = 1; i <= n; i ++) {
for(int j = 1; j < i; j ++) {
if(a[j] > a[i] && dp[j] > dp[i]) {
dp[i] = dp[j];
}
}
dp[i] ++;
max_ = max(max_, dp[i]);
if(dp[i] == 1) num[i] = 1;
}
for(int i = 1; i <= n; i ++) {
for(int j = 1; j < i; j ++) {
if(dp[i] == (dp[j] + 1) && a[i] < a[j]) num[i] += num[j];
if(dp[i] == dp[j] && a[i] == a[j]) num[i] = 0;
}
if(dp[i] == max_) sum += num[i];
}
printf("%d %d", max_, sum);
return 0;
}