POJ 1952 BUY LOW, BUY LOWER 最长上升子序列+dp+路径输出

题目:

http://poj.org/problem?id=1952

https://www.acwing.com/problem/content/316/

题意:

给定一段时间内股票的每日售价(正16位整数)。

你可以选择在任何一天购买股票。

每次你选择购买时,当前的股票价格必须严格低于你之前购买股票时的价格。

编写一个程序,确定你应该在哪些天购进股票,可以使得你能够购买股票的次数最大化。

输入格式

第1行包含整数 N,表示给出的股票价格的天数。

第2至最后一行,共包含 N 个整数,每行10个,最后一行可能不够10个,表示 N 天的股票价格。

同一行数之间用空格隔开。

输出格式

输出占一行,包含两个整数,分别表示最大买进股票次数以及可以达到最大买进次数的方案数。

如果两种方案的买入日序列不同,但是价格序列相同,则认为这是相同的方案(只计算一次)。

数据范围:

1<=N<=5000

 

(这道题本来是求最长下降子序列的,我在输入的时候把它反过来了,因此这里求最长上升子序列)

本来最长上升子序列可以用贪心+二分做的,但是这道题因为要路径输出,因此用贪心似乎不可以(反正我想了好久最后放弃了)

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<vector>
#include<queue>
#include<map>
#define ll long long 
#define ull unsigned long long 
using namespace std;
const int INF = 0x3f3f3f3f;
const int maxn = 5e3 + 7;
int dp[maxn], ways[maxn];
int num[maxn];
int main() {
	int n; cin >> n;
	for (int i = 1; i <= n; i++)
		scanf("%d", num + n - i + 1);//上升变下降
	ways[0] = 1;//用来初始化
	for (int i = 1; i <= n; i++) {
		for (int j = 0; j < i; j++) //dp[j]=0用来初始化
			if(num[i]>num[j])
				dp[i] = max(dp[i], dp[j] + 1);
		for (int j = 0; j < i; j++) {//ways[0]=0初始化
			if (dp[i] == dp[j] + 1 && num[i] > num[j])
				ways[i] += ways[j];
		}
		for (int j = 1; j < i; j++) {
			if (dp[i] == dp[j] && num[i] == num[j]) {//去重
				ways[i] -= ways[j];
			}
		}
        //去重不明白的话,模拟一下 1 1 2 1 2
	}
	int mx = 0, ans = 0;
	for (int i = 1; i <= n; i++) {
		if (dp[i] > mx) {
			mx = dp[i];
		}
	}
	for (int i = 1; i <= n; i++) {
		if (dp[i] == mx)
			ans += ways[i];
	}
	cout << mx << " " << ans << endl;

	return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值