1. 程式人生 > >HDU5532 Almost Sorted Array(最長上升子序列 or 瞎搞個做差的數組)

HDU5532 Almost Sorted Array(最長上升子序列 or 瞎搞個做差的數組)

algo problem 刪除 給定 子序列 中間 OS blank mes

題目鏈接:點我

題意:給定一個序列,詢問是否能刪除一個數讓它成為非遞減或者非遞增的序列。

   比如說 刪除後的序列是1 3 3 5 或者5 3 3 1 或者1 3 5 或者5 3 1 都可以。只要滿足刪掉某個數,構成非遞減或者非遞增,就輸出YES,如果不能就輸出NO

正解(LIS求最長上升子序列):

正著來一遍,反著來一遍 註意要用upper_bound即可:

代碼:

#include<bits/stdc++.h>
using namespace std;
int Maxlen(int a[],int n){
    int b[100010];
    memset(b,0,sizeof
(b)); int len = 0; for(int i = 0; i < n; i ++) { if(len == 0 ||a[i] >= b[len - 1]) { b[len] = a[i]; len ++; } else { int p = upper_bound(b,b + len,a[i]) - b; b[p] = a[i]; } }
return len; } int main(){ int t,n; for(scanf("%d",&t);t--;){ scanf("%d",&n); int a[100010],c[100010]; for(int i = 0 ; i < n ; i++){ scanf("%d",&a[i]); c[n-i-1] = a[i]; } int len = Maxlen(a,n); int len1 = Maxlen(c,n);
if(len >= n-1 || len1 >= n-1)puts("YES"); else puts("NO"); } }

如果想瞎搞也行。。。

因為刪除一個嘛,先證明刪除一個能不能是非遞減的(非遞增的把序列倒過來搞一次就行了)

首先,對一個序列前後兩個數做差

比如說序列

3 1 4 1 5 做差後(即1-3,4-1,1-4,5-1)是 -2,3,-3,4。發現有2個負數,那就不行。

如果序列是 3 1 1 5。 做差後是-2,0,4。發現有一個負數,是在頭部,可以刪掉

如果序列是5 6 3 ,7 7,做差後是 1,-3,4,0。發現有一個負數,而且可以跟左右兩邊的某個數相加變成正數,那麽這個3就可以刪掉。

如果序列是1 2 3 4,做差後是1,1,1,1 沒有負數,本身就可以是非遞減。

能看得出來:

做差後的序列:如果有2個及以上負數,那它肯定不可能是非遞減。

       如果有一個負數,它在頭或者尾,或者在中間而且可以跟左右兩邊任意一個數相加是正數,即可以是非遞減

       如果沒有負數,已經是非遞減

時間復雜度是O(N),額外需要O(N)的空間存做差後的數組

非遞增的話就把數組倒一下再來一次就行了。

代碼(很亂):

#include <cstdio>  
#include <cstring>  
#include <cmath>  
#include <cstdlib>  
#include <ctime>  
#include <iostream>  
#include <algorithm>  
#include <sstream>  
#include <string>  
#include <vector>  
#include <queue>  
#include <stack>  
#include <map>  
#include <set>  
#include <utility>  
#include <bitset>  

using namespace std;  
#define LL long long  
#define pb push_back  
#define mk make_pair  
#define pill pair<int, int>  
#define mst(a, b)    memset(a, b, sizeof a)  
#define REP(i, x, n)    for(int i = x; i <= n; ++i)
int main(){
    int t,n;
    for(scanf("%d",&t);t--;){
        scanf("%d",&n);
        int a[100010],b[100010],c[100010];
        for(int i = 0 ; i < n ; i++){
            scanf("%d",&a[i]);
            c[n-i-1] = a[i];
        }
        int f1 = 0,ard = -1;
        int s1 = 0,s2 = 0;
        for(int i = 1 ; i < n ; i++){
            b[i] = a[i] - a[i-1];
            if(b[i] < 0){
                 f1++;
                ard = i;
            }
            if(f1 == 2){
                break;
            }
        }
        if(f1 == 0){
            s1 = 1;
        }
        if(f1 == 1){
            if(ard == 1 || ard == n-1){
                s1 = 1;
            }
            else if(b[ard] + b[ard-1] >= 0 || b[ard] + b[ard+1] >= 0){
                s1 = 1;
            }
        }
        f1 = 0;
        ard = -1;
        //for(int i = 0 ; i < n ; i++)    printf("%d ",c[i]);
        for(int i = 1 ; i < n ; i++){
            b[i] = c[i] - c[i-1];
            if(b[i] < 0){
                 f1++;
                ard = i;
            }
            if(f1 == 2){
                break;
            }
        }
        if(f1 == 0){
            s2 = 1;
        }
        if(f1 == 1){
            if(ard == 1 || ard == n-1){
                s2 = 1;
            }
            else if(b[ard] + b[ard-1] >= 0 || b[ard] + b[ard+1] >= 0){
                s2 = 1;
            }
        }
        s1||s2?puts("YES"):puts("NO");//s1,s2分別代表在非遞減和非遞增可不可以滿足條件
    }
}

HDU5532 Almost Sorted Array(最長上升子序列 or 瞎搞個做差的數組)