poj 1952 buy low buy lower(DP)
描述 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 5005 using 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; }