题目连接:http://acm.hdu.edu.cn/contests/contest_showproblem.php?pid=1006&cid=646
题意:给一串序列,问是否可以通过删除一个元素使其成为单调序列
思路:
1、这题给了数据范围是n<=10^5,T<=2000,所以必须O(n)的效率通过。
2、因为要删除一个数,我们就需要找到应该删除哪个数,因此就要判断删除完以后是单调不降序列还是单调不增序列。
3、因为只能删除一个数,所以只有一个数是特殊数字(和其他数字的单调性不同),如果有多个特殊数字的话,即输出NO。
解法:所以这题在输入的过程中我们通过变量up来记录上升数字的个数,通过down来记录下降数字的个数,通过uppos来记录上升数字的位置,通过downpos来记录下降数字的位置,然后根据这四个变量分类讨论即可。
分类讨论:
① up>1&&down>1
这种情况就是有多个特殊数字,即输出NO即可。
② up==0||down==0||n<=3
这种情况下,全部是单调的,删除一个数字以后自然也是单调的,输出YES即可。或者删除一个数以后剩余的数不超过两个也一定是单调的。
③ up==1&&down==1
这种情况下,我们就要细想一下了:
第一种情况:显然我们只需要删除那个特殊的点即可,即abs(uppos-downpos)==1的时候输出YES。
那么当abs(uppos-dowpos)>1的时候一定是NO么?我们可以思考一下分下面三种情况:
Ⅰ、这样明显是NO。
Ⅱ、这样明显是YES。
Ⅲ、这样明显也是YES
所以这段代码实现应该是:
if(up==1&&down==1)
{
if(abs(uppos-downpos)==1)
{
pfs("YES");
continue;
}
else{
if(uppos==1||uppos==n-1||downpos==1||downpos==n-1)
{
pfs("YES");
continue;
}
else
{
pfs("NO");
continue;
}
}
}
up==1&&down==1的情况我们讨论完了,那么剩下来的就是up>1&&down==1和up==1down>1这两种情况了。
④ up>1&&down==1
这种情况在删除后应该为单调不降序列
仔细思考依旧如上存在两种情况,特殊的点在中间,特殊的点在两端:
中间:这种情况下,如图如果 a[downpos+1] >= a[downpos-1] 的时候或者 a[downpos] >= a[downpos-2] 的时候输出YES,其余输出NO。
在两端:如图很容易看出来,在两端的情况必然为YES。
⑤ up>1&&down==1
这种情况再删除后应该为是单调不增序列,和第四种情况正好相反,分类讨论的情况是一样的,分在两端和在中间两种情况。
AC代码:
/*
* test.cpp
*
* Created on: 2015-11-1
* Author: Ivan_w
*/
#include<iostream>
#include<stdio.h>
#include<string.h>
#include<math.h>
#include<algorithm>
#include<stdlib.h>
#include<queue>
#include<stack>
#include<map>
#include<vector>
#define mem(a) memset(a,0,sizeof(a))
#define pfn printf("\n")
#define ll __int64
#define pfd(a) printf("%d\n",a)
#define pf2d(a,b) printf("%d %d\n",a,b)
#define pf3d(a,b,c) printf("%d %d %d\n",a,b,c)
#define pfs(a) printf("%s\n",a)
#define sfd(a) scanf("%d",&a)
#define sf2d(a,b) scanf("%d%d",&a,&b)
#define sf3d(a,b,c) scanf("%d%d%d",&a,&b,&c)
#define sfs(a) scanf("%s",a)
#define sf scanf
#define pf printf
#define fr(i,n) for(int i=0;i<n;i++)
#define wang int
#define bo main
#define byebye return 0
#define bye return
const double PI = acos(-1.0);
const double e = exp(1.0);
template<class T> T gcd(T a, T b) { return b ? gcd(b, a % b) : a; }
template<class T> T lcm(T a, T b) { return a / gcd(a, b) * b; }
template<class T> inline T Min(T a, T b) { return a < b ? a : b; }
template<class T> inline T Max(T a, T b) { return a > b ? a : b; }
bool cmpbig(int a,int b){return a>b;}
bool cmpsmall(int a,int b){return a<b;}
using namespace std;
int a[101000];
wang bo(){
int t;
while(~sfd(t))
{
while(t--)
{
int n,up=0,down=0,uppos,downpos;
sfd(n);
for(int i=0;i<n;i++)
{
sfd(a[i]);
if(i>=1)
{
if(a[i]>a[i-1])
{
up++;
uppos=i;
}
else if(a[i]<a[i-1])
{
down++;
downpos=i;
}
}
}
if(up>1&&down>1)
{
pfs("NO");
continue;
}
else if(up==0||down==0||n<=3)
{
pfs("YES");
continue;
}
else if(up==1&&down==1)
{
if(abs(uppos-downpos)==1)
{
pfs("YES");
continue;
}
else{
if(uppos==1||uppos==n-1||downpos==1||downpos==n-1)
{
pfs("YES");
continue;
}
else
{
pfs("NO");
continue;
}
}
}
else if(up>1&&down==1)
{
if(downpos==1||downpos==n-1)
{
pfs("YES");
continue;
}
else{
if(a[downpos]>=a[downpos-2]||a[downpos+1]>=a[downpos-1])
{
pfs("YES");
continue;
}
else
{
pfs("NO");
continue;
}
}
}
else if(up==1&&down>1)
{
if(uppos==1||uppos==n-1)
{
pfs("YES");
continue;
}
else{
if(a[uppos]<=a[uppos-2]||a[uppos+1]<=a[uppos-1])
{
pfs("YES");
continue;
}
else
{
pfs("NO");
continue;
}
}
}
}
}
byebye;
}