[線性dp] 合唱隊形(最長上升子序列模型)

Y_puyu發表於2020-11-17

0. 前言

相關:

[線性dp] 最長上升子序列(模板題+最長上升子序列模型)

[線性dp] 怪盜基德的滑翔翼(最長上升子序列模型)

強相關:

[線性dp] 登山(最長上升子序列模型)

1. LIS 變種模型

482. 合唱隊形

在這裡插入圖片描述

重點: 線性 dpLIS 問題

思路:

  • 先嚴格上升、再嚴格下降。則正向求一遍 LIS、反向再求一遍 LIS,兩者相加再減去重複點 1 即可
  • [線性dp] 登山(最長上升子序列模型) 同源,踢出去最少的人,等價於找到最長的上升、下降子序列。就最後把答案 res 換成 n - res 就行了。其它 cv 即可
  • 時間複雜度: O ( n 2 ) O(n^2) O(n2)

本題為 NOIP2004 提高組原題。

正反兩遍再求和程式碼:

#include <iostream>
#include <algorithm>

using namespace std;

const int N = 1005;

int n;
int a[N];
int f[N], d[N];

int main() {
    cin >> n;
    for (int i = 0; i < n; ++i) cin >> a[i];
    
    for (int i = 0; i < n; ++i) {
        f[i] = d[i] = 1;
        for (int j = 0; j < i; ++j)
            if (a[i] > a[j]) 
                f[i] = max(f[i], f[j] + 1);
    }
    
    for (int i = n - 1; i >= 0; --i) {
        d[i] = 1;
        for (int j = n - 1; j >= i; --j) 
            if (a[i] > a[j])
                d[i] = max(d[i], d[j] + 1);
    }
    
    int res = 0;
    for (int i = 0; i < n; ++i) res = max(res, f[i] + d[i] - 1);
    cout << n - res << endl;
    return 0;
}

相關文章