题意:https://www.luogu.com.cn/problem/P1108
如果两个数列组成的数字完全相同,那我们说这两个数列相同。
求出最长下降子序列的方案数。
题解来自 wjyyy大神。
在dp过程中,f数组存的是最长下降子序列的长度,ff数组的下标i是以i结尾的意思,所以最长下降子序列(除了最后一位外)的数据已经丢失,因此不能在方案数相加时再判断是否能加。
我们从头来看,
- 如果一个数列的第一个数与另一个数列的第一个数相同,那么现在可以判断它们相等,即可以把其中一个删掉(在代码中的处理是t [ j ] =0)。当不同的数接在它的后面时,又可以将它们判断为两个数列,这是不互相影响的。因为两个数列都可以由这个相等的数列转移而来
- 如果一个数列的第一个数与另一个数列的第一个数不同,那么它们不等,且无论后面添加什么,都不相等,即不删去,则按照普通的判断继续做。
由上面的两点,我们已经把重复的删掉,这样可以防止重复计数。
#include <bits/stdc++.h> using namespace std; #define max(a,b) (a>b?a:b) int a[5009],f[5009],t[5009]; //a[i]是题目给的股票价格,f[i]是第i天最长的长度 //t[i]是以i结尾的方案 int main() { int n,maxn=0; cin>>n; for(int i=1;i<=n;i++) cin>>a[i],f[i]=1; for(int i=1;i<=n;i++) { for(int j=1;j<i;j++) { if(a[i]<a[j]) f[i]=max(f[i],f[j]+1); }//目前是正常求最长下降子序列 maxn=max(maxn,f[i]);//记下最长的长度 for(int j=1;j<i;j++) { if(f[i]==f[j]&&a[i]==a[j])//一样长而且数列完全一样 t[j]=0; else if(f[i]==f[j]+1&&a[i]<a[j])//可以接上前面的 t[i]+=t[j]; } if(!t[i]) t[i]=1;//为了后面的数转移 } int ans=0; for(int i=1;i<=n;i++) if(f[i]==maxn) ans+=t[i]; cout<<maxn<<" "<<ans; }