题目链接
翻译
让你统计"山"和“山谷"的总个数,要求这个总个数最少。
你可以修改某个数字为任意整数。
题解
首先对于初始的数组,统计一下山加上山谷的总数(cnt)
然后枚举第 (i) 个位置,现在要对第 (i) 个位置上的数字进行修改了。
最直接的想法就是,改了 (a[i]) 之后,哪些位置上的山顶和山谷的值会受到影响呢?
只有 (i-1,i,i+1) 这 (3) 个位置。
所以,在修改之前先减去这 (3) 个位置的影响,改了之后再加上影响用于更新最小值即可。
(a[i]) 的改法有 (5) 种情况(假设(a[i-1]) 和 (a[i+1]) 中较小值为 (xiao),较大值为 (da)
那么 (a[i]) 可以改为 xiao-1,xiao,xiao+1,da,da+1
这 (5) 种情况,这样就能把 (a[i]) 对 (i-1) 和 (i+1)
的影响都考虑到了。
然后 (cha) 的时候看了一下别人代码,好像有只需要改成 (a[i-1]) 和 (a[i+1]) 两者之一就可以的。。
代码
#include <bits/stdc++.h>
using namespace std;
const int N = 3e5;
int n,hills,valleys;
int a[N+10];
int calHill(int i){
if (i == 1 || i == n){
return 0;
}
if (a[i] > a[i-1] && a[i] > a[i+1]){
return 1;
}
return 0;
}
int calValley(int i){
if (i == 1 || i == n){
return 0;
}
if (a[i-1] > a[i] && a[i] < a[i+1]){
return 1;
}
return 0;
}
void sub(int i){
for (int j = -1;j <= 1; j++){
hills -= calHill(i+j);
valleys -= calValley(i+j);
}
}
void add(int i){
for (int j = -1;j <= 1; j++){
hills += calHill(i+j);
valleys += calValley(i+j);
}
}
int main(){
#ifdef LOCAL_DEFINE
freopen("in.txt", "r", stdin);
#endif
ios::sync_with_stdio(0),cin.tie(0);
int T;
cin >> T;
while (T--){
cin >> n;
hills = 0,valleys = 0;
for (int i = 1;i <= n; i++){
cin >> a[i];
}
for (int i = 2;i <= n-1;i++){
hills += calHill(i);
valleys += calValley(i);
}
int mi = hills + valleys;
for (int i = 2;i <= n-1; i++){
sub(i);
int xiao = a[i-1],da = a[i+1];
if (xiao > da){
swap(xiao,da);
}
int temp = a[i];
a[i] = xiao-1;
if (a[i] < 1){
a[i] = 1;
}
add(i);
mi = min(mi,hills + valleys);
sub(i);
a[i] = xiao+1;
if (a[i] > 1e9){
a[i] = 1e9;
}
add(i);
mi = min(mi,hills + valleys);
sub(i);
a[i] = da+1;
if (a[i] > 1e9){
a[i] = 1e9;
}
add(i);
mi = min(mi,hills + valleys);
sub(i);
a[i] = xiao;
add(i);
mi = min(mi,hills + valleys);
sub(i);
a[i] = da;
add(i);
mi = min(mi,hills + valleys);
sub(i);
a[i] = temp;
add(i);
}
cout << mi << endl;
}
return 0;
}