dp(最大升序列:二分查找时间优化nlogn)

We are all familiar with sorting algorithms: quick sort, merge sort, heap sort, insertion sort, selection sort, bubble sort, etc. But sometimes it is an overkill to use these algorithms for an almost sorted array.

We say an array is sorted if its elements are in non-decreasing order or non-increasing order. We say an array is almost sorted if we can remove exactly one element from it, and the remaining array is sorted. Now you are given an array a1,a2,,an

, is it almost sorted?
InputThe first line contains an integer T indicating the total number of test cases. Each test case starts with an integer n in one line, then one line with n integers a1,a2,,an.

1T2000
2n105
1ai105
There are at most 20 test cases with n>1000.OutputFor each test case, please output "`YES`" if it is almost sorted. Otherwise, output "`NO`" (both without quotes).Sample Input
3
3
2 1 7
3
3 2 1
5
3 1 4 1 5
Sample Output
YES
YES
NO

思路:找最长非降子序列或最长非增子序列的个数是否与原数列的个数最多 少1个 , 即为yes。。


#include <iostream>
#include <iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<algorithm>
#include <stdio.h>
#include <string.h>
#include <vector>
#include <set>
using namespace std;
int   v[509] , w[509] , dp[100009] , a[100009] , dpp[100009], b[100009];
int len1 , len2 ;

int halfsearch(int *dp , int r , int x) // 返回数组dp中第一个比a[i]大的数的下标+1
{
    int l = 1 , mid ;
    while(r >= l)
    {
        mid = (l + r) >> 1 ;
        if(dp[mid] <= x)
        {

            l = mid + 1 ;
        }
        else
        {
            r = mid - 1 ;
        }
    }
    return l ;
}


int main()
{
    int n  ;
    scanf("%d" , &n);
    while(n--)
    {
        int m ;
        scanf("%d" , &m);
        for(int i = 1 ; i <= m ; i++)
        {
            scanf("%d" , &a[i]);
            b[m - i + 1] = a[i]; // 这里巧妙的将求最长非增子序列转为求最长非减子序列。
        }
        dp[1] = a[1] ;
        len1 = 1 ;
        for(int i = 2 ; i <= m ; i++)
        {
            if(a[i] >= dp[len1]) // 如果小于该数组的最大一个就插入后面
                dp[++len1] = a[i];
            else//将第一个比a[i]大的数替换成a[i];
            {
                dp[halfsearch(dp , len1 , a[i])] = a[i];
            }
        }
        if(len1 >= m - 1)
            printf("YES\n");
        else
        {
            dpp[1] = b[1] ;
            len2 = 1 ;
            for(int i = 2 ; i <= m ; i++)
            {
                if(b[i] >= dpp[len2])
                    dpp[++len2] = b[i];
                else
                {
                    dpp[halfsearch(dpp , len2 , b[i])] = b[i];
                }
            }

            if(len2 >= m - 1)
                printf("YES\n");
            else
                printf("NO\n");


        }


    }

    return 0;
}


猜你喜欢

转载自www.cnblogs.com/nonames/p/11228547.html