1. 程式人生 > WINDOWS開發 >AcWing 1490. 最長上升子串 模擬優化

AcWing 1490. 最長上升子串 模擬優化

地址https://www.acwing.com/solution/content/15094/

給出一個長度為 n 的由正整數構成的序列,你需要從中刪除一個正整數,很顯然你有很多種刪除方式,你需要對刪除這個正整數以後的序列求其最長上升子串,請問在所有刪除方案中,最長的上升子串長度是多少。

這裡給出最長上升子串的定義:即對於序列中連續的若干個正整數,滿足 ai+1>ai,則稱這連續的若干個整數構成的子串為上升子串,在所有的上升子串中,長度最長的稱為最長上升子串。

輸入格式
輸入第一行僅包含一個正整數 n,表示給出的序列的長度。

接下來一行有 n 個正整數,即這個序列,中間用空格隔開。

輸出格式
輸出僅包含一個正整數,即刪除一個數字之後的最長上升子串長度。

資料範圍
1≤n≤105,1≤ai≤105 輸入樣例: 5 2 1 3 2 5 輸出樣例: 3

演算法1
首先考慮使用暴力遍歷解答,逐個刪除某個數字然後雙指標統計上升子串的長度。
過程中我們會發現,如果刪除該元素 對於上升子串沒有提升的長度 則可以考慮剪枝。
對於上升子串沒有提升的長度的定義呢 就是該數字的左邊的數小於該數字右邊的數。
那麼進一步的優化,如果我們首先統計以該數字為結尾和以該數字為開始 的上升子串的長度,
可以減少不少的計算量。

類似如此
a b c d 如果我們實現統計了 以各個元素為結尾的最長上升子串長度 ai bi ci di
統計了 以各個元素為起始的最長上升子串長度 aj bj cj dj.

那麼如果 a < c 我們可以嘗試刪除b,得到子串長度就是 ai+bj;
但如果b < d 我們可以嘗試刪除c,得到的子串長度就是bi+dj;

程式碼實現見Y總得示例程式碼

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>

using namespace std;

const int N = 100010;

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

int main()
{
    scanf("%d",&n);
    
for (int i = 1; i <= n; i ++ ) scanf("%d",&a[i]); // 預處理f[i]:以i結尾的單調上升子串的最大長度 for (int i = 1; i <= n; i ++ ) if (a[i] > a[i - 1]) f[i] = f[i - 1] + 1; else f[i] = 1; // 預處理g[i]:以i開頭的單調上升子串的最大長度 for (int i = n; i; i -- ) if (a[i] < a[i + 1]) g[i] = g[i + 1] + 1; else g[i] = 1; int res = 0; // 列舉刪除哪個數 for (int i = 1; i <= n; i ++ ) if (a[i - 1] >= a[i + 1]) res = max(res,max(f[i - 1],g[i + 1])); else res = max(res,f[i - 1] + g[i + 1]); printf("%d\n",res); return 0; }