题目链接
https://www.luogu.org/problemnew/show/P2687
分析
题目要求你买最多天数的股票,很容易发现实际上就是求最长下降子序列,但是怎么计算方案数有点烦人
我们用$f[i]$表示以第$i$天结尾的最长下降子序列长度,$g[i]$表示以转移到以第$i$天结尾的最长下降子序列可用的方案数
那么我们可以这样进行状态转移:
1 2 3 4 5 6 7 8 9 10
| for(ri i=1;i<=n;i++){ for(ri j=0;j<i;j++){ if(c[j]>c[i]&&f[i]==f[j]+1){ g[i]+=g[j]; } else if(c[i]==c[j]&&f[i]==f[j]){ g[j]=0; } } }
|
注意最后答案不一定是g[N],因为可能有些不是以第N天结尾的最长下降子序列长度也与答案一样
代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55
| #include <cstdio> #include <cstdlib> #include <cstring> #include <cctype> #include <algorithm> #include <queue> #define ll double #define ri register int using std::min; using std::max; template <class T>inline void read(T &x){ x=0;int ne=0;char c; while(!isdigit(c=getchar()))ne=c=='-'; x=c-48; while(isdigit(c=getchar()))x=x*10+c-48; x=ne?-x:x;return ; } const int maxn=5005; const int inf=0x7fffffff; int n; ll cnt=0; ll g[maxn]; ll c[maxn],f[maxn],ans=-inf; int main(){ read(n); for(ri i=1;i<=n;i++){ scanf("%lf",&c[i]); } memset(f,0,sizeof(f)); c[0]=inf; for(ri i=1;i<=n;i++){ for(ri j=0;j<i;j++){ if(c[j]>c[i]){ f[i]=max(f[i],f[j]+1); } } ans=max(ans,f[i]); } g[0]=1; for(ri i=1;i<=n;i++){ for(ri j=0;j<i;j++){ if(c[j]>c[i]&&f[i]==f[j]+1){ g[i]+=g[j]; } else if(c[i]==c[j]&&f[i]==f[j]){ g[j]=0; } } } for(ri i=1;i<=n;i++)if(f[i]==ans)cnt+=g[i]; printf("%.0lf %.0lf\n",ans,cnt); return 0; }
|