题目背景
小强和阿米巴是好朋友。
题目描述
小强很喜欢数列。有一天,他心血来潮,写下了一个数列。
阿米巴也很喜欢数列。但是他只喜欢其中一种:波动数列。
一个长度为n的波动数列满足对于任何i(1 <= i < n),均有:
a[2i-1] <= a[2i] 且 a[2i] >= a[2i+1](若存在) 或者
a[2i-1] >= a[2i] 且 a[2i] <= a[2i+1](若存在)
阿米巴把他的喜好告诉了小强。小强便打算稍作修改,以让这个数列成为波动数列。他想知道,能否通过仅修改一个数(或不修改),使得原数列变成波动数列。
输入输出格式
输入格式:
输入包含多组数据。
每组数据包含两行。
第一行一个整数n表示数列的长度。
接下来一行,n个整数,表示一个数列。
输出格式:
对于每一组输入,输出一行Yes或No,含义如题目所示。
输入输出样例
5 1 2 3 2 1 5 1 2 3 4 5
Yes No
说明
对于30%的数据,n <= 10
对于另外30%的数据,m <= 1000
对于100%的数据,n <= 10^5,m <= 10^9
其中m = max|a[i]|(数列中绝对值的最大值)
贪心策略:
由于波动序列本质上只有 2 种,所以对于每一种波动序列, 求出将原序列变为这种波动序列最少需要修改几次。
如果两 个值的较小值不大于 1,则输出”Yes“,否则输出”No“。
问题变为求原序列变为某种波动序列需要的最小修改次数。 从前向后扫,如果遇到某个元素不满足要求,则将该元素修 改为 ∞ 和 −∞ 中满足要求的那个,并将计数器加一。
最后计数器的值就是修改需要的最小次数。 总复杂度 O(n)。
#include<iostream>
#include<algorithm>
#include<cstdio>
#define MAXN 100010
using namespace std;
int n,a[MAXN];
inline int read(){
int date=0,w=1;char c=0;
while(c<'0'||c>'9'){if(c=='-')w=-1;c=getchar();}
while(c>='0'&&c<='9'){date=date*10+c-'0';c=getchar();}
return date*w;
}
void work(){
int s=0;
bool f=false,ans=true;
for(int i=1;i<=n;i++)a[i]=read();
for(int i=2;i<=n;i++,f=!f)
if(a[i]!=a[i-1]&&a[i]>a[i-1]!=f){
s++;
if(s>1){ans=false;break;}
else{i++;f=!f;}
}
if(ans)printf("Yes\n");
else{
f=true;
ans=true;
s=0;
for(int i=2;i<=n;i++,f=!f)
if(a[i]!=a[i-1]&&a[i]>a[i-1]!=f){
s++;
if(s>1){ans=false;break;}
else{i++;f=!f;}
}
if(ans)printf("Yes\n");
else printf("No\n");
}
}
int main(){
while(scanf("%d",&n)==1){
if(n<=3)printf("Yes\n");
else work();
}
return 0;
}