CF1467B Hills And Valleys 题解

题目传送门
解题思路:
题目中说只能修改一个数字的值,那么显然我们就可以枚举每个 \(i\ \left(2\le i \le n\right)\) ,那么我们修改第 \(i\) 个数字的话,显然我们修改之后只有 \(i-1,i,i+1\) 三个位置的状态发生了改变,我们只要预处理不修改的答案总和就可以了。
修改的时候我们会发现,要想让修改之后的答案最小,我们就需要将这个数字的值修改成前一个数的值或者后一个数字的值,也可能是两者的平均数。
最后记得注意修改第 \(1\) 个和修改第 \(n\) 个的情况,因为这个我WA了3发
Tips:记得多组数据清空数组。
代码:

#include<cstdio>
#include<cstring>
#define maxn 300039
#define min(a,b) ((a)<(b)?(a):(b))
using namespace std;
//#define debug
typedef int Type;
inline Type read(){
	Type sum=0;
	int flag=0;
	char c=getchar();
	while((c<'0'||c>'9')&&c!='-') c=getchar();
	if(c=='-') c=getchar(),flag=1;
	while('0'<=c&&c<='9'){
		sum=(sum<<1)+(sum<<3)+(c^48);
		c=getchar();
	}
	if(flag) return -sum;
	return sum;
}
int T;
int n,a[maxn];
int cheg(int x){
	if(x==1||x==n) return 0;
	return (a[(x)]<a[(x+1)]&&a[(x)]<a[(x-1)]);
}
int ches(int x){
	if(x==1||x==n) return 0;
	return (a[(x)]>a[(x+1)]&&a[(x)]>a[(x-1)]);
}
void work(){
	memset(a,0,sizeof(a));
	n=read();
	for(int i=1;i<=n;i++)
	    a[i]=read();
	int sum,ans;
	sum=0;
	for(int i=2;i<n;i++){
	    if(cheg(i)) sum++;
		if(ches(i)) sum++;
	}
	ans=sum;
	int tmp,pre,end;
	for(int i=2;i<n;i++){
		tmp=a[i];
		pre=cheg(i)+cheg(i-1)+cheg(i+1)+ches(i)+ches(i-1)+ches(i+1);
		
		a[i]=a[i-1];
		end=cheg(i)+cheg(i-1)+cheg(i+1)+ches(i)+ches(i-1)+ches(i+1);
		ans=min(ans,sum-pre+end);
		
		a[i]=a[i+1];
		end=cheg(i)+cheg(i-1)+cheg(i+1)+ches(i)+ches(i-1)+ches(i+1);
		ans=min(ans,sum-pre+end);
		
		a[i]=(a[i+1]+a[i-1])>>1;
		end=cheg(i)+cheg(i-1)+cheg(i+1)+ches(i)+ches(i-1)+ches(i+1);
		ans=min(ans,sum-pre+end);
		
		a[i]=tmp;
	}
	pre=cheg(2)+ches(2);
	a[1]=a[2];
	end=cheg(2)+ches(2);
	ans=min(ans,sum-pre+end);
	
	pre=cheg(n-1)+ches(n-1);
	a[n]=a[n-1];
	end=cheg(n-1)+ches(n-1);
	ans=min(ans,sum-pre+end);
	
	printf("%d\n",ans);
	return;
}
int main(){
    T=read();
    while(T--) work();
	return 0;
}
posted @ 2021-02-15 22:37  jiangtaizhe001  阅读(33)  评论(0编辑  收藏  举报