DP - 最長上升子序列 - Defense Lines - UVA - 1471

DP - 最長上升子序列 - Defense Lines - UVA - 1471

題意:

Tn使T組測試數據。\\給定一個長度爲n的序列,要求刪除其中的一部分連續的序列,使得剩下的序列當中的連續上升子序列儘量的長。\\要求刪除過後,連續上升子序列最大的長度。

Sample Input:
2
9
5 3 4 9 2 8 6 7 1
7
1 2 3 10 4 5 6

Output:
4
6

數據範圍:

T<=25n<=200000T<=25,n<=200000。

Time limit3000msTime \ limit:3000 ms

題解:

本題特殊在連續:刪除一部分連續序列,求剩下部分連續上升子序列的長度。

a[i]a[j]i<ja[i]<a[j](i,j)O(n2)O(n)O(n3)最暴力的做法是枚舉以a[i]結尾的最長連續上升子序列和以a[j]開頭的最長連續上升子序列,i<j\\若a[i]<a[j]則可以將區間(i,j)內的元素刪除,最大長度就是兩部分序列長度的和。\\枚舉的部分是O(n^2)的,計算兩部分長度是O(n)的,總的時間複雜度是O(n^3)。

O(n2)計算兩部分連續上升子序列的長度這一步驟可以利用前綴和預處理,這樣能優化到O(n^2)。

l[i]a[i]r[i]a[i]用l[i]數組記錄以元素a[i]結尾的連續最長上升子序列的長度,r[i]記錄以a[i]開頭的連續最長上升子序列的長度。

調q[i]i這樣,我們可以用單調隊列q[i]優化,維護長度爲i的連續最長上升子序列的末尾元素。
a[i]qa[i]lena[i]對於每個元素a[i],在q中查找第一個大於等於a[i]的位置len,這個位置以a[i]結尾的序列的長度。
r[i]a[i]anslen+r[i]1a[i]l[i]r[i]是以a[i]開頭的連續最長上升子序列的長度,用ans維護len+r[i]-1的最大值。\\最後將a[i]插入到隊列的l[i]的位置。


代碼:

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

#define ll long long
#define inf 0x3f3f3f3f

using namespace std;

const int N=2e5+10;

int T,n,a[N],l[N],r[N],q[N];

int main()
{
    cin>>T;
    while(T--)
    {
        memset(l,0,sizeof l);
        memset(r,0,sizeof r);
        memset(q,0x3f,sizeof q);
        
        scanf("%d",&n);
        for(int i=1;i<=n;i++) scanf("%d",&a[i]);

        for(int i=1;i<=n;i++)
        {
            l[i]=1;
            if(a[i]>a[i-1])
                l[i]+=l[i-1];
        }
        for(int i=n;i;i--)
        {
            r[i]=1;
            if(a[i]<a[i+1])
                r[i]+=r[i+1];
        }
        
        int ans=0;
        for(int i=1;i<=n;i++)
        {
            int len=lower_bound(q+1,q+1+n,a[i])-q;
            ans=max(ans,r[i]+len-1);
            q[l[i]]=min(q[l[i]],a[i]);
        }

        cout<<ans<<endl;
    }

    return 0;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章