1. 程式人生 > >最長下降子序列 + 最長的方案數

最長下降子序列 + 最長的方案數

連結:http://exam.upc.edu.cn/problem.php?id=1824

題意:求最長下降子序列的長度,和該長度的最長下降子序列有多少個

思路:o(n^2)求最長下降子序列,統計個數時兩個狀態轉移方程一是統計個數的通用方程:if(a[i] < a[j] && dp[i] == dp[j + 1])cnt[i] += cnt[j]

另一個是如果當前點和之前的點是相等的,且dp[i] == dp[j]那麼當前點的所有情況中一定是包括了之前點的方案數,大於等於之前的點。固清空之前點的情況,保留當前點的結果

程式碼:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <sstream>
#include <string>
#include <algorithm>
#include <list>
#include <map>
#include <vector>
#include <queue>
#include <stack>
#include <cmath>
#include <cstdlib>
using namespace std;
map<int,int>mapp;
int a[5005];
int dp[5005];
int cnt[5005];
int main()
{
    //freopen("in.txt","r",stdin);
    int n;
    scanf("%d",&n);
    for(int i = 0; i < n; i ++)
    {
        scanf("%d",&a[i]);
    }
    for(int i = 0; i <n; i ++)
    {
        dp[i] = 1;
        for(int j = 0; j < i; j ++)
        {
            if(a[j] >a[i])
            {
                dp[i] = max(dp[i],dp[j] + 1);
            }
        }
        if(dp[i] == 1)
        cnt[i] = 1;
    }
    int maxn = 0;
    for(int i =  0; i < n; i ++)
    {
        maxn = max(maxn,dp[i]);
    }
    printf("%d ",maxn);


    for(int i = 0; i < n; i ++)
    {

        for(int j = 0; j < i ; j ++)
        {
            if(a[j] > a[i] && dp[i] == dp[j] + 1)
            {
                cnt[i] += cnt[j];

            }
           if(a[j] == a[i] &&dp[i] == dp[j])
           {
               cnt[j] = 0;
           }
        }
    }
    int ans = 0;
    for(int i = 0; i < n; i ++)
    {
        if(dp[i] == maxn)
        ans += cnt[i];
    }
    printf("%d\n",ans);
    return 0;
}