P1108 低價購買
阿新 • • 發佈:2021-11-10
https://www.luogu.com.cn/problem/P1108
設 \(f_i,g_i\) 表示以 \(i\) 結尾的最長下降子序列最大長度,和以 \(i\) 結尾、以 \(f_i\) 為長的不重複子序列方案數。這裡的不重複不僅要在結尾為 \(i\) 的集合中不重,而且跟 \(1\sim i-1\) 的也不重複。
首先可以發現,\(f_i\) 一定不能從 \(\le p\) 的 \(j\) 轉移過來,\(p\) 表示 \(a_i\) 之前第一個等於 \(a_i\) 的數的下標。原因是 \(p\) 能統計的 \(i\) 也能統計,就會重複了,所以不能從 \(\le p\) 的轉移,也不需要。
同時我們發現,符合要求的子序列的開頭數字 \(x\)
#include <bits/stdc++.h> using namespace std; const int N=5e3+5,V=(1<<16)+5; int n,a[N],f[N],g[N],bk[V]; bool isfi[N]; int main(){ cin>>n; for(int i=1;i<=n;i++){ cin>>a[i]; isfi[i]=!bk[a[i]]; bk[a[i]]++; } for(int i=1;i<=n;i++){ f[i]=g[i]=1; for(int j=i-1;j&&a[j]!=a[i];j--){ if(a[j]>a[i]){ if(f[j]+1>f[i]){ f[i]=f[j]+1; g[i]=g[j]; } else if(f[j]+1==f[i])g[i]+=g[j]; } } if(f[i]==1&&!isfi[i])g[i]=0; } int id=0,sum=0; for(int i=1;i<=n;i++){ if(f[id]<f[i])id=i,sum=g[i]; else if(f[id]==f[i])sum+=g[i]; } cout<<f[id]<<' '<<sum; }