【dp】PKU 1952 buy low,buy lower
题目链接: http://poj.org/problem?id=1952
Usaco 4.3.1
Buy Low, Buy Lower
By 小兔齐齐
描述
“逢低吸纳”是炒股的一条成功秘诀。如果你想成为一个成功的投资者,就要遵守这条秘诀:
"逢低吸纳,越低越买"
这句话的意思是:每次你购买股票时的股价一定要比你上次购买时的股价低.按照这个规则购买股票的次数越多越好,看看你最多能按这个规则买几次。
给定连续的N天中每天的股价。你可以在任何一天购买一次股票,但是购买时的股价一定要比你上次购买时的股价低。写一个程序,求出最多能买几次股票。
以下面这个表为例, 某几天的股价是:
天数 1 2 3 4 5 6 7 8 9 10 11 12
股价 68 69 54 64 68 64 70 67 78 62 98 87
这个例子中, 聪明的投资者(按上面的定义),如果每次买股票时的股价都比上一次买时低,那么他最多能买4次股票。一种买法如下(可能有其他的买法):
天数 2 5 6 10
股价 69 68 64 62
格式
PROGRAM NAME: buylow
INPUT FORMAT:
(file buylow.in)
第1行: N (1 <= N <=5000), 表示能买股票的天数。
第2行以下: N个正整数 (可能分多行) ,第i个正整数表示第i天的股价. 这些正整数大小不会超过longint(pascal)/long(c++).
OUTPUT FORMAT:
(file buylow.out)
只有一行,输出两个整数:
能够买进股票的天数 长度达到这个值的股票购买方案数量
在计算方案的数量的时候,如果两个方案的股价序列相同,那么这样的两个方案被认为是相同的(只能算做一个方案)。因此,两个不同的天数序列可能产生同一个股价序列,这样只能计算一次。
SAMPLE INPUT
12
68 69 54 64 68 64 70 67
78 62 98 87
SAMPLE OUTPUT
4 2
非常漂亮的动归题目,程序里面的问题都是自己找出来的,做了3天,比较爽。这个题目说白了就是先让你求最长递减序列的长度,然后去掉重复的。这个题目关键在于去掉重复的。a[i]表示所储存的元素,然后是dp[i]表示到第i个元素的时候(包括这个元素)的最长递减序列的长度,count[i]是用来记录到第i个元素长度是dp[i]的所有结果有多少个。
现在分析去重问题。
这是这组数据的结果,dp[i]的求法就不做赘述了。然后是count[i],如果dp[i]==1说明了,这个数必然是从1到i最大的那个,也就是count[i]=1。反之必然存在至少为2的count[i]。如果是a[j]>a[i]&&dp[j]+1==dp[i],这个就能说明这个元素j参与了构成这个最长的下降序列,现在的问题就是如果j元素后面出现了相同的元素怎么办,当然结果就是count[i]不加这个j的count[j],因为你在前面已经加进去了。还有一个问题,如果第i号元素前面出现了,我们就直接将前面的那个元素的count赋值为0.具体的看下面的代码。
1 #include<iostream> 2 #include<algorithm> 3 #include<string> 4 #include<vector> 5 #include<set> 6 #include<queue> 7 #include<map> 8 #include<stack> 9 #include<iterator> 10 #include<cstdio> 11 #include<cstring> 12 #include<cstdlib> 13 #include<cmath> 14 using namespace std; 15 typedef long long ll; 16 typedef unsigned long long ull; 17 #define clr(c) memset(c, 0, sizeof(c)); 18 #define pi acos(-1.0) 19 const int INF = 0x3f3f3f3f; 20 const int mod = 1e9 + 7; 21 const double eps = 1e-8; 22 typedef struct point{ 23 int x, y; 24 bool operator < (const point& p) const{ 25 if (x == p.x) return y < p.y; 26 else return x < p.x; 27 } 28 bool operator >(const point& p) const{ 29 return p < *this; 30 } 31 }p; 32 33 int n; 34 int a[5005]; 35 int dp[5005]; 36 int cnt[5005]; 37 38 int main(){ 39 while(~scanf("%d", &n)){ 40 for(int i = 0; i < n; i++) scanf("%d", &a[i]); 41 42 for(int i = 0; i < n; i++) dp[i] = 1; 43 int ans = 0; 44 for(int i = 0; i < n; i++){ 45 for(int j = 0; j < i; j++){ 46 if(a[i] < a[j] && dp[j]+1 > dp[i]) dp[i] = dp[j]+1; 47 } 48 if(ans < dp[i]) ans = dp[i]; 49 } 50 51 for(int i = 0; i < n; i++) cnt[i] = 0; 52 for(int i = 0; i < n; i++){ 53 for(int j = 0; j < i; j++){ 54 if(a[i] == a[j]) cnt[j] = 0; 55 } 56 if(dp[i] == 1) cnt[i] = 1; 57 else{ 58 for(int j = 0; j < i; j++){ 59 if(a[i] < a[j] && dp[j]+1 == dp[i]) cnt[i] += cnt[j]; 60 } 61 } 62 } 63 //for(int i = 0; i < n; i++) printf("%d ", dp[i]); printf("\n"); 64 //for(int i = 0; i < n; i++) printf("%d ", cnt[i]); printf("\n"); 65 66 int sum = 0; 67 for(int i = 0; i < n; i++) if(dp[i] == ans) sum += cnt[i]; 68 printf("%d %d\n", ans, sum); 69 } 70 71 return 0; 72 }