HDU-5532 Almost Sorted Array (最长上升子序列 or 模拟)

传送门

Almost Sorted Array

Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 262144/262144 K (Java/Others)
Total Submission(s): 7512    Accepted Submission(s): 1763


Problem Description
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?
 

Input
The 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.
 

Output
For each test case, please output "`YES`" if it is almost sorted. Otherwise, output "`NO`" (both without quotes).
 

Sample Input
 
  
332 1 733 2 153 1 4 1 5
 

Sample Output
 
  
YESYESNO

题目大意:

给你一段序列,求是否满足删掉一个元素后,序列变为非递减或非递增序列。

分析:(两种方法)LIS ,模拟

  • 第一种,套用LIS模板(有重复元素),模板讲解链接:https://blog.csdn.net/GodJing007/article/details/81047330    分别对正向和反向序列求LI S-right, LIS-left.若其一满足大于等于序列长度减一,即可输出YES.                                             代码如下:                                                                                                                                                                       
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 100;

int a[N], b[N];
int lis(int a[], int n){
	int dp[N];
	dp[0] = a[0];
	int len = 0;
	for(int i = 1; i < n; i++){
		if(a[i] >= dp[len]){
			dp[++len] = a[i];
		}else{
			int k = upper_bound(dp, dp+len+1, a[i])-dp;
			dp[k] = a[i];
		}
	}
	return len+1;
}

int main(){
	 ios::sync_with_stdio(false);   //注意“开挂”输入输出,不然会超时
    cin.tie(0);
    cout.tie(0);

	int t;
	cin >> t;
	while(t--){
		int n;
		cin >> n;
		for(int i = 0;  i < n; i++){
			cin >> a[i];
			b[n-i-1] = a[i];
		}
		if(lis(a,n) >= n-1 || lis(b,n) >= n-1){
			cout << "YES" << endl;
		}else{
			cout << "NO" << endl;
		}
	}
}

  • 第二种:模拟,分别假设序列是递增或递减的,然后逐元素判断是否满足条件,               注意代码红色部分注释


#include <bits/stdc++.h> 
using namespace std;
#define MM(a) memset(a,0,sizeof(a))

typedef long long LL;
typedef unsigned long long ULL;
const int maxn = 1e5+5;
const int mod = 1000000007;
const int INF = 0x3f3f3f3f;
 
int arr[maxn];
int m;

bool judge1()///从小到大
{
    int sum = 0;     //sum变量代表删除元素的次数
    arr[0] = -INF, arr[m+1] = INF;
    for(int i=2; i<=m; i++)      //逐元素遍历,
    {
        if(arr[i] < arr[i-1])    //如果找到不符合顺序的,删除a[i]或者a[i-1],(此时a[i+1]变为a[i]).       
        {                        //使a[1]到a[i]符合顺序
            if(sum == 1)        //如果已经删除过,则返回失败。
            return false;
            sum++;             
            if(arr[i+1]>=arr[i-1] || arr[i]>=arr[i-2]) //这句判断非常重要,意思是删除掉arr[i]后1 ~ i有序,即arr[i+1]>=arr[i-1]
                continue;                              //或者删除掉arr[i-1]后数组1 ~ i有序,即arr[i]>=arr[i-1].         
            else                                       //若两者都不满足,返回false;
                return false;
        }
    }
    return true;
}
bool judge2()///从大到小                    //判断同上
{
    int sum = 0;
    arr[0] = INF, arr[m+1] = -INF;
    for(int i=2; i<=m; i++)
    {
        if(arr[i] > arr[i-1])
        {
            if(sum == 1)
            return false;
            sum++;
            if(arr[i+1]<=arr[i-1] || arr[i]<=arr[i-2])
                continue;
            else
                return false;
        }
    }
    return true;
}
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d",&m);
        for(int i=1; i<=m; i++)
            scanf("%d",&arr[i]);
        if(judge1() || judge2())
            puts("YES");
        else
            puts("NO");
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/godjing007/article/details/81047163