前言
假期第一篇题解
题目
题目描述
给定一段时间内股票的每日售价(正16位整数)。
你可以选择在任何一天购买股票。
每次你选择购买时,当前的股票价格必须严格低于你之前购买股票时的价格。
编写一个程序,确定你应该在哪些天购进股票,可以使得你能够购买股票的次数最大化。
例如,下面是一个股票价格时间表:
Day 1 2 3 4 5 6 7 8 9 10 11 12
Price 68 69 54 64 68 64 70 67 78 62 98 87
如果每次购买都必须遵循当前股票价格严格低于之前购买股票时的价格,那么投资者最多可以购买四次该股票。
买进方案之一为:
Day 2 5 6 10
Price 69 68 64 62
输入格式
第1行包含整数 N,表示给出的股票价格的天数。
第2至最后一行,共包含 N 个整数,每行10个,最后一行可能不够10个,表示 N 天的股票价格。
同一行数之间用空格隔开。
输出格式
输出占一行,包含两个整数,分别表示最大买进股票次数以及可以达到最大买进次数的方案数。
如果两种方案的买入日序列不同,但是价格序列相同,则认为这是相同的方案(只计算一次)。
样例
样例1输入
12
68 69 54 64 68 64 70 67 78 62 98 87
样例1输出
4 2
样例2输入
5
4 3 2 1 1
样例2输出
4 1
数据范围与提示
1≤N≤5000
------------------------------------------------气愤的分割线-------------------------------------------------------------
第一问,明显LIS,直接摸板,关键在于第二问
第二问
设数组F来表示从1到i的方案总数,F[i]=1
那么如果前一个a[j]+1==a[i],那么可以确定F[i]是按照F[j]得来的,并且这时如果a[j]>a[i],可以再买一张股票,符合要求,那么就把F[j]加到F[i]里
if(a[j]>a[i]&&dp[i]==dp[j]+1)
{
F[i]+=F[j];
}
而如果a[j]==a[i]且dp[j]==dp[i],那么F[i]的方案一定在F[j]里,此时直接把F[i]置为0,并不会影响后面的答案(加0没影响噻~)
所以
if(a[i]==a[j]&&dp[i]==dp[j])
{
F[i]=0;
}
最后再用一个循环判断如果dp[i]==maxi,则ans+=F[i]
完整代码
#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
long long n,a[5010],dp[5010],k[5010],maxi=0,ans=0;
int main()
{
memset(a,0,sizeof(a));
memset(dp,0,sizeof(dp));
scanf("%lld",&n);
if(n==1)
{
for(int i=1;i<2;i++)
{
scanf("%lld",&a[i]);
}
printf("1 1");
return 0;
}//加了个特判骗了9分qwq
for(int i=1;i<=n;i++)
{
scanf("%lld",&a[i]);
dp[i]=1;
for(int j=1;j<i;j++)
{
if(a[j]>a[i]&&dp[j]+1>dp[i])
{
dp[i]=dp[j]+1;
maxi=max(maxi,dp[i]);
}
}
}
for(int i=1;i<=n;i++)
{
if(dp[i]==1)
{
k[i]=1;
}
for(int j=1;j<i;j++)
{
if(a[j]>a[i]&&dp[i]==dp[j]+1)
{
k[i]+=k[j];
}
if(a[i]==a[j]&&dp[i]==dp[j])
{
k[i]=0;
}
}
}
for(int i=1;i<=n;i++)
{
if(dp[i]==maxi)
{
ans+=k[i];
}
}
printf("%lld %lld",maxi,ans);
return 0;
}
完