[題解] [洛谷P1108] 低價購買

wxy3265發表於2024-04-25

[洛谷P1108] 低價購買

題目描述

給定一個序列,求這個序列的最長嚴格下降子序列的長度和數量,特別的是如果兩個子序列只要每個數都相同,無論原來的位置,都算作同一個子序列。

輸入格式

第一行共一個整數 \(n(1 \leq n \leq 5000)\) 表示序列長度。

第二行一行 \(n\) 個整數,表示序列的每個元素。保證是大小不超過 \(2^{16}\) 的正整數。

輸出格式

輸出共一行兩個整數,分別為最大購買次數和擁有最大購買次數的方案數(資料保證 \(\leq 2^{31}\) )。

題解

水藍題一道。資料範圍允許 \(O(n ^ 2)\) 複雜度做法,故用最基礎的求 \(lis\) 的dp方法即可解決第一問。

問題的關鍵是如何統計出得到 \(lis\) 的方案數。自然地可以想到在轉移狀態的同時記錄一下得到當前狀態的方案數 \(cnt_i\) ,如果找到了更優狀態,就把前一個狀態的方案數繼承過來,如果找到了和當前狀態一樣優的子狀態,就把那個狀態的方案數疊加上去即可。

最後剩下的問題就是重複的方案,實際上這中情況僅限於前一個狀態對應的最後一位 \(a_j\) 相等的情況,不難發現對於兩個狀態相同的 \(j_1, j_2(j_1 < j_2)\) 來說,\(j_1\) 的方案是包括在 \(j_2\) 中的,因此我們只統計較為靠後的狀態的方案數即可,可以透過倒著迴圈和打標記的方法解決。最後統計答案的時候用類似的方法將所有不同的狀態等於 \(ans\) 的不相等的方案數累加即可。

AC程式碼

#include <iostream>
#define int long long
using namespace std;

const int MAXN = 5003;
const int MAXA = 1e5 + 3;

int n, a[MAXN];

int f[MAXN], cnt[MAXN]; // 分別記錄長度和方案數
int vis[MAXA]; // 標記是否出現過相同狀態

signed main() {
    cin >> n;
    // 輸入與初始化
    for (int i = 1; i <= n; i++) {
        cin >> a[i];
        cnt[i] = f[i] = 1;
    }
    int ans = 0;
    for (int i = 1; i <= n; i++) {
        for (int j = 1; j < i; j++) vis[a[j]] = 0; // 重置標記
        for (int j = i - 1; j > 0; j--) {
            if (a[i] < a[j]) { // 合法的狀態
                if (f[j] + 1 > f[i]) { // 更優的狀態轉移
                    f[i] = f[j] + 1;
                    // 繼承方案數
                    vis[a[j]] = f[i];
                    cnt[i] = cnt[j];
                } else if (f[j] + 1 == f[i]) { // 與當前狀態一樣優的狀態
                    // 累加方案數
                    if (vis[a[j]] != f[i]) cnt[i] += cnt[j]; // 不是相同的狀態就累加方案數
                    vis[a[j]] = f[i];
                }
            }
        }
        ans = max(ans, f[i]); // 更新答案
    }
    int anscnt = 0; // 統計方案數
    for (int i = 1; i <= n; i++) vis[a[i]] = false; // 初始化標記
    for (int i = n; i > 0; i--) {
        if (vis[a[i]]) continue; // 如果統計過相同的狀態就跳過
        if (f[i] == ans) anscnt += cnt[i], vis[a[i]] = true; // 如果是最優狀態就累加到答案裡
    }
    // 輸出答案
    cout << ans << ' ' << anscnt << '\n';
    return 0;
}

相關文章