低价购买(LIS方案统计)

题意:https://www.luogu.com.cn/problem/P1108

如果两个数列组成的数字完全相同,那我们说这两个数列相同。

求出最长下降子序列的方案数。


题解来自 wjyyy大神。

dp过程中,f数组存的是最长下降子序列的长度,ff数组的下标i是以i结尾的意思,所以最长下降子序列(除了最后一位外)的数据已经丢失,因此不能在方案数相加时再判断是否能加。

我们从头来看,

  1. 如果一个数列的第一个数与另一个数列的第一个数相同,那么现在可以判断它们相等,即可以把其中一个删掉(在代码中的处理是t [ j ] =0)。当不同的数接在它的后面时,又可以将它们判断为两个数列,这是不互相影响的。因为两个数列都可以由这个相等的数列转移而来
  2. 如果一个数列的第一个数与另一个数列的第一个数不同,那么它们不等,且无论后面添加什么,都不相等,即不删去,则按照普通的判断继续做。

由上面的两点,我们已经把重复的删掉,这样可以防止重复计数。

#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;
} 
原文地址:https://www.cnblogs.com/iss-ue/p/12501951.html