本题有两个问题
最大买进股票次数:LDS,最长下降子序列
最大买进次数的方案数:
最大买进次数的方案数
注意一个限制条件
- 买入日序列不同,价格序列相同,认为方案相同
方案数推导
求方案数,我们知道其实就是一个拓扑序列的推导,所以我们要设置一些入度为0的点,让他们的现有方案数=1,通过删除这些点和他们的出度,不断地找到入度为0的点,更新
那么对于一个最长上升子序列来说,刚开始入度为0的点 就是 以该点为结尾的lis长度==1的点,设置他们的方案数==1,就可以求出所有方案数了
原问题:lis的所有方案数
子问题:以a[i]为结尾的lds的所有方案
状态定义:c[i]:以a[i]为结尾的lds的所有方案数
划分依据:以a[i]为结尾的lds的倒数第二个元素
状态计算:所有以a[i]为结尾的lds的倒数第二个元素
- f[i]==f[1]+1 c[i]+=c[1]
- f[i]==f[2]+1 c[i]+=c[2]
- ...
限制条件
由于只要价格序列相同,就说明方案是相同的
那么对于一个点a[i]前面,如果有a[j]==a[i]并且f[i]==f[j],说明以a[i]为结尾的lis长度==以a[j]为结尾的lds长度,并且a[i]==a[j]的话,说明他们重复计算了方案,那么应该把前面的c[j]设为0
为什么判断条件f[i]==f[j]
说明以a[i]为结尾的lds长度==以a[j]为结尾的lds长度
我们的目的是去重,第二个问题答案是最长lds的方案数
在j前面,以a[j]这个数字为结尾的lds被重复计数了两次,只有f[i]==f[j]时,说明他们的lds长度相同,应该去除
如果f[i]>f[j],以a[i]为结尾的lds长度不是以a[j]为结尾的lds长度,方案不重复
f[i]==f[j],方案重复
为什么设置c[j],并让他为0
如果设置c[i]==0,第二重循环仍会继续,最后的c[i]不一定为0,没有意义,仍会重复
设置c[j]==0,说明去重掉了所有重复的方案,对于c[i]来说,重复的方案就是c[j],因为i在后面,1~j的所有元素i,j都可以使用,而j~i的所有元素仅i可以使用
重复方案个数=c[j]
不重复方案个数=c[i]-c[j]
#include <iostream>
#include <algorithm>
using namespace std;
const int N=5010;
int f[N];
int c[N];
int a[N];
int main()
{
int n;
cin>>n;
for(int i=1;i<=n;i++)
cin>>a[i];
int res=0;
for(int i=1;i<=n;i++)
{
f[i]=1;
for(int j=1;j<i;j++)
if(a[i]<a[j])
f[i]=max(f[i],f[j]+1);
for(int j=1;j<i;j++)
{
if(a[i]<a[j]&&f[i]==f[j]+1)
c[i]+=c[j];
if(a[i]==a[j]&&f[i]==f[j])
c[j]=0;
}
if(f[i]==1)
c[i]=1;
res=max(res,f[i]);
}
int cnt=0;
for(int i=1;i<=n;i++)
if(f[i]==res)
cnt+=c[i];
cout<<res<<' '<<cnt;
return 0;
}