poj 1952 buy low buy lower(DP)

来源:互联网 发布:java通配符下限 编辑:程序博客网 时间:2024/04/29 19:03

描述 Description

“低买高卖”是在神牛证券市场上成功的秘诀的一半。作为一个好的投资者,你必须还遵守下面这条建议:

“逢低吸纳,越低越买”

每次你购买股票的时候,你必须以比上次购买这只股票的价格更低的价格来购买这只股票。购买比上次便宜的股票的次数越多越好!你的目标是计算像这样的低价进仓最多可以进行多少次。

数据会给你一只股票在一段时期内每日的交易价格(16位正整数)。你可以选择在任何一天购买股票。每次你选择购买股票的时候,股价必须严格小于你上次购买股票的股价。写一个程序来确定在那些日子购买股票来最大化你购买的次数。

下面是一张股价表:
日期 1   2   3   4   5   6   7   8   9   10 11 12
价格 68 69 54 64 68 64 70 67 78 62 98 87

一个最好的投资者(至少在这个问题里是这样)可以最多以比上一次的价格更低的价格购买四次股票。一种可行的购买方案是(当然,也有其他的购买方案):

日期 2   5   6   10
价格 69 68 64 62

输入 Input

※ 第一行:N(1 ≤ N ≤ 5,000),给定股价的天数。
※ 第二、三行及后面:一个有 N 个用空格隔开的整数的序列,除了最后一行比较少之外,每一行有十个数字。

输出 Output

在一行之内输出两个整数:
※ 最长的下降价格序列的长度
※ 有这样长度的下降序列的个数

在序列个数的统计过程中,两个可能的解将会被判作相同(以及只计算一次),如果它们的序列是完全相同的两个串,也就是说,比较连续的价格的时候它们“看上去相同”。于是,两个不同的“购买日期”序列如果得到的是同一个“价格”序列,就应该被看作是一个解

*思路:首先要确定最长下降子序列再就是记录最长下降子序列的个数(同样的最长子序列不可重复计数)单纯求最长子序列用dp很快就解决。难点在于求其个数与去重。以下数组time计算当前阶段最下降长子序列的个数

#include<iostream>#include<cstring>#define num 5005using namespace std;int main(){int n,i,l=0,s=0,k,dp[num],a[num],time[num];cin>>n;for(i=1;i<=n;i++)cin>>a[i];for(i=1;i<=n;i++){dp[i]=1;time[i]=1;//初始化}for(i=2;i<=n;i++)for(k=i-1;k>=1;k--){if(a[k]>a[i]){if(dp[i]<dp[k]+1){dp[i]=dp[k]+1;time[i]=time[k];//此时a[i]与其前面的数构成最长下降子序列,所以前面time[i]=time[k]}else if(dp[i]==dp[k]+1)time[i]+=time[k];//此时到i时产生与前面最长下降子序列长度相同的子序列但是a[k]!=a[i],所以到i时最长下降子序列个数是新构成的(包括a[i])与旧的(没有a[i])数量的和。}else if(a[k]==a[i]){if(dp[i]==1) time[i]=0;//假如碰到一个前面已经出现的数并且这个数的dp[i]==1说明他与前面相等的数之间并没有构成新的最长下降子序列,所以与前面的数等价,令其time[i]=0防止重复计数。例如:3 2 1 3 2 1此时两个3等价第二个3的dp值等于1,但是3 2 6 3 2中两个3不等价此时第二个3的dp值显然不等于1.break;}}for(i=1;i<=n;i++)if(dp[i]>l)l=dp[i];for(i=1;i<=n;i++)if(dp[i]==l)s+=time[i];cout<<l<<' '<<s<<endl;return 0;}


原创粉丝点击