11064: 【原1064】小M爱炒股
题目
题目描述
author: duruofei 原OJ链接:https://acm.sjtu.edu.cn/OnlineJudge-old/problem/1064
Description
小M最近喜欢上了炒股。作为一个爱思考的孩子,小M发现了一条炒股秘诀——"逢低吸纳,越低越买"!
这句话的意思是:每次你购买股票时的股价一定要比你上次购买时的股价低,按照这个规则购买股票的次数越多越好,看看你最多能按这个规则买几次。给定连续的N天中每天的股价。你可以在任何一天购买一次股票,但是购买时的股价一定要比你上次购买时的股价低。小M想让你帮他写一个程序,求出最多能买几次股票。
以下面这个表为例, 某几天的股价是:
(Here put the table)
这个例子中, 小M如果每次买股票时的股价都比上一次买时低,那么他最多能买4次股票。一种买法如下(可能有其他的买法):
(Here put the table)
Input Format
第1行: N (\( 1 \leq N \leq 5000 \) ), 表示能买股票的天数。
第2行以下: N个正整数 (可能分多行) ,第i个正整数表示第i天的股价. 这些正整数大小不会超过longint(pascal)/long(c++)
Output Format
只有一行,输出两个整数:
能够买进股票的天数 长度达到这个值的股票购买方案数量
在计算方案的数量的时候,如果两个方案的股价序列相同,那么这样的两个方案被认为是相同的(只能算做一个方案)。因此,两个不同的天数序列可能产生同一个股价序列,这样只能计算一次。
Sample Input
12
68 69 54 64 68 64 70 67
78 62 98 87
Sample Output
4 2
FineArtz's solution
/* 小M爱炒股 */
#include <iostream>
#include <cassert>
using namespace std;
class Bignum{
public:
int len = 1;
long long data[1005] = {0};
long long &operator [](int x){
return data[x];
}
void clear(){
for (int i = 1; i <= len; ++i)
data[i] = 0;
len = 1;
}
Bignum &operator =(const Bignum &b){
clear();
len = b.len;
for (int i = 1; i <= len; ++i)
data[i] = b.data[i];
return *this;
}
};
Bignum operator +(const Bignum &b1, const Bignum &b2){
Bignum c;
c.len = max(b1.len, b2.len);
for (int i = 1; i <= c.len; ++i){
c.data[i] = c.data[i] + b1.data[i] + b2.data[i];
c.data[i + 1] += c.data[i] / 10;
c.data[i] %= 10;
}
++c.len;
while (c.data[c.len] != 0){
c.data[c.len + 1] += c.data[c.len] / 10;
c.data[c.len] %= 10;
++c.len;
}
if (c.data[c.len] == 0 && c.len != 1)
--c.len;
return c;
}
long long a[5005], len;
int n;
long long t[5005];
Bignum c, cnt[5005];
int main(){
cin >> n;
for (int i = 1; i <= n; ++i){
cin >> a[i];
t[i] = 1;
cnt[i][1] = 1;
}
len = 0;
for (int i = 1; i <= n; ++i){
for (int j = 1; j < i; ++j){
if (a[j] > a[i]){
if (t[i] < t[j] + 1){
t[i] = t[j] + 1;
cnt[i] = cnt[j];
}
else if (t[i] == t[j] + 1)
cnt[i] = cnt[i] + cnt[j];
}
}
for (int j = 1; j < i; ++j){
if (a[i] == a[j] && t[i] == t[j])
cnt[j].clear();
}
if (t[i] > len)
len = t[i];
}
for (int i = 1; i <= n; ++i){
if (t[i] == len)
c = c + cnt[i];
}
cout << len << ' ';
for (int i = c.len; i >= 1; --i)
cout << c[i];
cout << endl;
return 0;
}
yyong119's solution
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int MAX_N = 5010;
int n, ans = 1;
int a[MAX_N], num[MAX_N], f[MAX_N], cnt[MAX_N][110], check[MAX_N << 2];
void add(int *x, int *y) {
int carries = 0, length = 1, z[110] = {0};
while (length <= x[0] || length <= y[0]) {
z[length] = x[length] + y[length] + carries;
carries = z[length] / 10;
z[length] = z[length] % 10;
length++;
}
z[length] = carries;
if (!z[length]) length--;
x[0] = length;
for (int i = 1; i <= length; ++i) x[i] = z[i];
}
int main() {
scanf("%d", &n);
for (int i = 1; i <= n; ++i) {
scanf("%d", &a[i]);
f[i] = 1;
}
for (int i = 2; i <= n; ++i)
for (int j = 1; j < i; ++j)
if (a[i] < a[j]) f[i] = max(f[i], f[j] + 1);
for (int i = 1; i <= n; ++i) ans = max(ans, f[i]);
printf("%d ", ans);
for (int i = 1; i <= n; ++i) {
if (f[i] == 1) cnt[i][0] = cnt[i][1] = 1;
else {
memset(check, 0, sizeof(check));
cnt[i][0] = 1;
for (int j = i - 1; j > 0; --j)
if (f[j] + 1 == f[i] && !check[a[j]] && a[i] < a[j]) {
add(cnt[i], cnt[j]);
check[a[j]] = 1;
}
}
}
memset(check, 0, sizeof(check));
for (int i = n; i > 0; --i)
if (f[i] == ans && !check[a[i]]) {
add(num, cnt[i]);
check[a[i]] = 1;
}
for (int i = num[0]; i >= 1; --i) printf("%d", num[i]);
return 0;
}