题目描述 Description
逢低吸纳”是炒股的一条成功秘诀。如果你想成为一个成功的投资者,就要遵守这条秘诀:
“逢低吸纳,越低越买”
这句话的意思是:每次你购买股票时的股价一定要比你上次购买时的股价低.按照这个规则购买股票的次数越多越好,看看你最多能按这个规则买几次。
给定连续的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
输入描述 Input Description
第1行: N (1 <= N <= 5000), 表示能买股票的天数。
第2行以下: N个正整数 (可能分多行) ,第i个正整数表示第i天的股价. 这些正整数大小不会超过longint(pascal)/long(c++).
输出描述 Output Description
只有一行,输出两个整数:
能够买进股票的天数和长度达到这个值的股票购买方案数量
在计算方案的数量的时候,如果两个方案的股价序列相同,那么这样的两个方案被认为是相同的(只能算做一个方案)。因此,两个不同的天数序列可能产生同一个股价序列,这样只能计算一次。
样例输入 Sample Input
12
68 69 54 64 68 64 70 67 78 62 98 87
样例输出 Sample Output
4 2
数据范围及提示 Data Size & Hint
见描述
思路
1丶 最长下降子序列模板
2丶统计方案数,由于方案数很大要用高精,还要判重
开一个二维数组sum[i][]储存在a[i]这个数时的方案数,
判重用一个bool数组
对于 sum[i]+sum[j] (a[i] < a[j]&&!b[a[j]]&&f[i]==f[j]+1)
只要标记了a[j] sum[i]就不会+sum[j]
这样先处理所有方案数,最后找f[i]==ans的方案数加起来就是总方案数
具体细节见代码
#include<cstdio>
#include<cstring>
#include<iostream>
#define MAXN 5010
using namespace std;
int a[MAXN],n,sum[MAXN][110],ansf[MAXN];
int f[MAXN],ans=1;
bool b[MAXN*10];
inline void read(int&x) {
int f=1;x=0;char c=getchar();
while(c>'9'||c<'0') {if(c=='-') f=-1;c=getchar();}
while(c>='0'&&c<='9') x=10*x+c-48,c=getchar();
x*=f;
}
inline void add(int *x,int *y) {
int len=1,c[110]={0},t=0;
while(len<=x[0]||len<=y[0]) {
c[len]=x[len]+y[len]+t;
t=c[len]/10;
c[len]%=10;
len++;
}
c[len]=t;
while(!c[len]) len--;
x[0]=len;
for(int i=1;i<=len;i++) x[i]=c[i];
}
int main() {
read(n);
for(int i=1;i<=n;i++) read(a[i]),f[i]=1;
for(int i=2;i<=n;i++)
for(int j=1;j<i;j++) {
if(a[j]>a[i]) {
f[i]=max(f[i],f[j]+1);
ans=max(ans,f[i]);
}
}//处理最长下降子序列
for(int i=1;i<=n;i++) {
if(f[i]==1) {
sum[i][0]=1;
sum[i][1]=1;
} //数组初始化 如果为1 说明这是一个 头
//就是说在a[i]之前没有比这个数更大的数
//那么从f[i]开始方案数为1
else {
memset(b,false,sizeof b);
sum[i][0]=1;
for(int j=i-1;j>=1;j--) {
if(a[i]<a[j]&&!b[a[j]]&&f[i]==f[j]+1) {
add(sum[i],sum[j]);
b[a[j]]=true;
}// 因为a[i]<a[j] 那么sum[i]=sum[i]+sum[j]
}
}
}
memset(b,false,sizeof b);
for(int i=n;i>=1;i--) {
if(f[i]==ans&&!b[a[i]]) {//找最长的下降子序列,方案数相加
add(ansf,sum[i]);
b[a[i]]=true;
}
}
printf("%d ",ans);
for(int i=ansf[0];i>=1;i--) printf("%d",ansf[i]);
return 0;
}