1. 程式人生 > >洛谷P1108 低價購買題解

洛谷P1108 低價購買題解

序列 ns2 每一個 解決 價格 const mat 沒有 方程

看到“你必須用低於你上次購買它的價格購買它”,有沒有想到什麽?沒錯,又是LIS,倒過來的LIS,所以我們只要把讀入的序列倒過來就可以求LIS了,第一問解決。
首先要厘清的是,對於這一題第二問貌似用\(nlog_{2}n\)的算法不是很好,因為我們需要序列中每一個位置可以接成LIS的長度。再看看數據範圍,會發現\(n^2\)完全可做。仔細想一想,不難發現第二問其實也是個\(DP\):若\(f[i]\)表示以\(i\)位置為結尾的LIS的長度,\(c[i]\)表示序列\(1\)~\(i\)位置按照最優選擇的方案數,則狀態轉移方程\(c[i]=\sum\limits_{1\leqslant j<i,a[i]>a[j],f[i]=f[j]+1}c[j]\)

,同時還要去重\(c[i]-=\sum\limits_{1\leqslant j<i,a[i]=a[j],f[i]=f[j]}c[j]\)
上代碼:

#include <iostream>
#include <algorithm>

using namespace std;

const int N = 5005;

int n, a[N], f[N], c[N], ans1, ans2;

int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(0);
    cin >> n;
    for
(int i = 1; i <= n; i++) cin >> a[n+1-i]; for(int i = 1; i <= n; i++) { \\常規n^2解法 f[i] = 1; for(int j = 1; j < i; j++) if(a[i]>a[j]) f[i] = max(f[i], f[j]+1); ans1 = max(ans1, f[i]); } for(int i = 1; i <= n; i++) { if(f[i] == 1
) c[i] = 1; \\初始化 for(int j = 1; j < i; j++) { if(f[i] == f[j] && a[i] == a[j]) c[i] -= c[j]; \\去重 if(f[i] == f[j]+1 && a[i] > a[j]) c[i] += c[j]; \\狀態轉移 } } for(int i = 1; i <= n; i++) if(f[i] == ans1) ans2 += c[i]; \\統計答案 cout << ans1 << " " << ans2; return 0; }

洛谷P1108 低價購買題解