P1108 低價購買 (DP)

題目

P1108 低價購買c++

解析

這題作的我身心俱憊,差點自閉。
當我WA了N發後,終於明白了這句話的意思git

當二種方案「看起來同樣」時(就是說它們構成的價格隊列同樣的時候),這2種方案被認爲是相同的。spa

這題有兩問,第一問顯然最長嚴格降低子序列,一看數據範圍:5000,跟最長嚴格上升子序列同樣,\(n^2\)直接寫就行。code

第二問求方案數,方案數也是用dp作
轉移方程隊列

//j<i
if (f[i] == f[j] + 1 && a[j] > a[i]) cnt[i] += cnt[j];

這裏還要注意一下相同這種狀況,
若是對於兩個位置\(i,j(j<i)\)來講,
\(f[i]==f[j]\&\&a[i]==a[j]\),那就說明到\(i\)與到\(j\)的這兩個最長降低子序列是相同的,算一種狀況(顯然吧應該)。
又由於咱們以前把部分算過一次貢獻,再也不算一遍,那咱們就直接不要它了,因此get

if (f[i] == f[j] && a[i] == a[j]) cnt[i] = 0;

代碼

#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10;
int n, ans, sum;
int a[N], b[N], f[N], cnt[N];

template<class T>inline void read(T &x) {
    x = 0; int f = 0; char ch = getchar();
    while (!isdigit(ch)) f |= (ch == '-'), ch = getchar();
    while (isdigit(ch)) x = x * 10 + ch - '0', ch = getchar();
    x = f ? -x : x;
    return;
}

int main() {
    read(n);
    for (int i = 1; i <= n; ++i) read(a[i]), b[i] = a[i];
    sort(b + 1, b + 1 + n);
    int len = unique(b + 1, b + 1 + n) - b - 1;
    for (int i = 1; i <= n; ++i) a[i] = lower_bound(b + 1, b + 1 + len, a[i]) - b;
    for (int i = 1; i <= n; ++i) {
        f[i] = 1;
        for (int j = 1; j <= i; ++j)
            if (a[j] > a[i]) f[i] = max(f[i], f[j] + 1);
    }
    for (int i = 1; i <= n; ++i) ans = max(f[i], ans);
    for (int i = 1; i <= n; ++i) {
        if (f[i] == 1) cnt[i] = 1;
        for (int j = 1; j < i; ++j) {
            if (f[i] == f[j] + 1 && a[j] > a[i]) cnt[i] += cnt[j];
            if (f[i] == f[j] && a[i] == a[j]) cnt[i] = 0;
        } 
        if (f[i] == ans) sum += cnt[i];
    }
    printf("%d %d", ans, sum);
    return 0;
}
相關文章
相關標籤/搜索