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

探讨了如何确定一个数组是否可以通过删除一个元素变成非递增或非递减排列的方法,提供了两种解决方案:最长递增子序列算法及模拟算法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

传送门

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.

1≤T≤2000
2≤n≤105
1≤ai≤105
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.youkuaiyun.com/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;
}如果找到不符合顺序的,删除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;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值