题目:https://www.luogu.org/problemnew/show/1108
思路:
这题有两种方法,第一种用动态规划,另一种用二分答案,这里介绍的是动态规划方法。
首先这题其实就是最长下降序列+统计方案数
a[i]表示第i种股票
b[i]表示前i个数的最长下降序列长度
f[i]表示到b[i]的方案个数
如果(b[j]+1=b[i])and(a[i]<a[j]) 也就是满足不下降且可以到达这里,那么f[i]=f[i]+f[j];但是我们会发现,如果前面有两种价格相等的股票,且到这两种股票的最长下降序列长度相等,也就是方案重复,那么此时的f[j]=0;
动态转移方程
f[i]+=(a[i]<a[j]&&b[j]+1==b[i])?f[j]:(a[i]==a[j]&&b[i]==b[j])?-f[i]:0;
废话不多说,上代码!
#include<cstdio> #include<cstring> #define k freopen #define r(i,a,b) for (int i=a;i<=b;i++)//循环 using namespace std;int n,ans1,ans2;//ans1是最长下降序列的长度,ans2是方案数 long long a[5001],b[5001],f[5001];//前面已经解释过了 int max(int x,int y)//推荐还是自己定义比较好 { return x>y?x:y; } void LRZ()//输入 { ans1=1; scanf("%d",&n); r(i,1,n) scanf("%d",&a[i]),b[i]=1;//最长下降 } void LDS()//b[i]的值,用于理解 { r(i,1,n) printf("%d ",b[i]); } void dp() { r(i,1,n) { r(j,1,i-1) if (a[j]>a[i]&&b[j]+1>b[i])//先把到i的最长下降序列求下来 { b[i]=b[j]+1; ans1=max(ans1,b[i]);//取下最大值 } if (b[i]==1) f[i]=1;//如果它的长度是1,那么它的方案数也是一,因为没有长度为0的序列 r(j,1,i-1)//从1到i-1 f[i]+=(a[i]<a[j]&&b[j]+1==b[i])?f[j]:(a[i]==a[j]&&b[i]==b[j])?-f[i]:0;//动态转移 } } void print() { printf("%d ",ans1); r(i,1,n) if (b[i]==ans1) ans2+=f[i];//把所有的方案加在一起 printf("%d",ans2);//输出 } int main() { LRZ(); dp(); print(); }