HDU5532 Almost Sorted Array(最长上升子序列 or 瞎搞个做差的数组)

题目链接:点我

题意:给定一个序列,询问是否能删除一个数让它成为非递减或者非递增的序列。

   比如说 删除后的序列是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分别代表在非递减和非递增可不可以满足条件
    }
}

原文地址:https://www.cnblogs.com/Esquecer/p/9013331.html

时间: 2024-08-29 03:18:12

HDU5532 Almost Sorted Array(最长上升子序列 or 瞎搞个做差的数组)的相关文章

HDU-5532 Almost Sorted Array (LIS)

题目大意:给一个n个数的序列,问这个序列删掉一个数后是否有序. 题目分析:找最长上升子序列和最长下降子序列,只要有一个的长度不小于n-1即可. 代码如下: # include<iostream> # include<cstdio> # include<cmath> # include<vector> # include<list> # include<queue> # include<map> # include<s

HDU5532 Almost Sorted Array

Almost Sorted Array Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 262144/262144 K (Java/Others)Total Submission(s): 9982    Accepted Submission(s): 2329 Problem Description We are all familiar with sorting algorithms: quick sort, merge sort

算法 - 求一个数组的最长递减子序列(C++)

//**************************************************************************************************** // // 求一个数组的最长递减子序列 - C++ - by Chimomo // // 题目: 求一个数组的最长递减子序列,比方{8, 14, 6, 2, 8, 14, 3, 2, 7, 4, 7, 2, 8, 101, 23, 6, 1, 2, 1, 1}的最长递减子序列为{14.8,3.

最长公共子序列(LCS)

最长公共子序列,英文缩写为LCS(Longest Common Subsequence).其定义是,一个序列 S ,如果分别是两个或多个已知序列的子序列,且是所有符合此条件序列中最长的,则 S 称为已知序列的最长公共子序列.而最长公共子串(要求连续)和最长公共子序列是不同的.       最长公共子序列是一个十分实用的问题,它可以描述两段文字之间的"相似度",即它们的雷同程度,从而能够用来辨别抄袭.对一段文字进行修改之后,计算改动前后文字的最长公共子序列,将除此子序列外的部分提取出来,

最长公共子序列(LCS)、最长递增子序列(LIS)、最长递增公共子序列(LICS)

最长公共子序列(LCS) [问题] 求两字符序列的最长公共字符子序列 问题描述:字符序列的子序列是指从给定字符序列中随意地(不一定连续)去掉若干个字符(可能一个也不去掉)后所形成的字符序列.令给定的字符序列X=“x0,x1,…,xm-1”,序列Y=“y0,y1,…,yk-1”是X的子序列,存在X的一个严格递增下标序列<i0,i1,…,ik-1>,使得对所有的j=0,1,…,k-1,有xij=yj.例如,X=“ABCBDAB”,Y=“BCDB”是X的一个子序列. 考虑最长公共子序列问题如何分解成

最长公共子序列(仅借助数组dp本身在O(m+n)时间内构造最长公共子序列)

算法课上机作业,想复杂了.. 给定2个序列X={x1,x2,…,xm}和Y={y1,y2,…,yn},找出X和Y的最长公共子序列. 改进LCS函数,不使用数组b而仅借助数组c本身在O(m+n)时间内构造最长公共子序列. 原来的代码: void LCSLength(char *x ,char *y,int m,int n, int **c, int **b) {        int i ,j;        for (i = 1; i <= m; i++) c[i][0] = 0;       

HDU 1025 最长上升子序列

首先根据第一个数排序,然后可以得到一串第二个数组成的序列,因为第一个由大到小排列,所以第二组中取到的数据,后面的不能比前面的小才不会形成交叉,那么也就是求这个新序列的最长公共子序列 这里要用到最长上升子序列的nlogn的算法,新建一个数组保存所有合理的数据的数组g,比如g数组中有了1,4,6,加进来一个3 , 那么4可以被3代替因为在同一个位置尽可能小能容纳的数据个数就会越多,越能找到更长的序列,这个找位置的过程就用二分搜索logn的复杂度 注意一点,我是因为这个好久没做出....就是边数大于1

动态规划解决最长公共子序列问题(转)

原文链接 动态规划法 经常会遇到复杂问题不能简单地分解成几个子问题,而会分解出一系列的子问题.简单地采用把大问题分解成子问题,并综合子问题的解导出大问题的解的方法,问题求解耗时会按问题规模呈幂级数增加. 解决思想: 为了节约重复求相同子问题的时间,引入一个数组,不管它们是否对最终解有用,把所有子问题的解存于该数组中,这就是动态规划法所采用的基本方法. [问题] 求两字符序列的最长公共字符子序列 问题描述:字符序列的子序列是指从给定字符序列中随意地(不一定连续)去掉若干个字符(可能一个也不去掉)后

动态规划解最长公共子序列问题(转)

 动态规划法 经常会遇到复杂问题不能简单地分解成几个子问题,而会分解出一系列的子问题.简单地采用把大问题分解成子问题,并综合子问题的解导出大问题的解的方法,问题求解耗时会按问题规模呈幂级数增加. 为了节约重复求相同子问题的时间,引入一个数组,不管它们是否对最终解有用,把所有子问题的解存于该数组中,这就是动态规划法所采用的基本方法. [问题] 求两字符序列的最长公共字符子序列 问题描述:字符序列的子序列是指从给定字符序列中随意地(不一定连续)去掉若干个字符(可能一个也不去掉)后所形成的字符序列