题意:给定你一个长度为n的序列,你有两种操作,给这个序列的后缀加一或者减一,序列的后缀定义和字符串的后缀定义相同,还有你开始在所有的操作开始的时候,选择把一个数变成任意的数,这个操作不计入总的操作次数,然后问你最少需要操作几次,才能将这个序列都变成相等的数。
思路:如果不看那个额外的操作,我们想把 a 1 a_1 a1和 a 2 , a 3 , . . . . a n a_2,a_3,....a_n a2,a3,....an都变成相等的,那么就一定要先把 a 2 , a 3 , . . . . a n a_2,a_3,....a_n a2,a3,....an变成相等的,同理 a 2 a_2 a2和 a 3 , a 4 , . . . . a n a_3,a_4,....a_n a3,a4,....an也是这个道理,所以我们想把这些数变成相等的所花费的最少的操作一定是,相邻的两个数的绝对值之差的和。
再看加上了初始的这个操作,把某个数变成任意数,肯定也不是乱变,我们一定要把他变成他左边或者右边的数才能对这个最少操作次数起到贡献,于是我们可以比较把中间这个数变成两侧的某一数后减少的操作次数最多的就是我们要找的最优的,因为一开始总的次数其实是固定住的。
代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MAXN = 2e5 + 7;
ll a[MAXN];
int main(){
int t;
scanf("%d",&t);
while(t--){
int n;
scanf("%d",&n);
for(int i = 1;i <= n;i ++) scanf("%lld",&a[i]);
ll maxx = 0;
for(int i = 1;i <= n;i ++){
if(i == 1) maxx = max(maxx,abs(a[i]-a[i+1]));
else if(i == n) maxx = max(maxx,abs(a[i]-a[i-1]));
else {
ll t = abs(a[i]-a[i-1]) + abs(a[i]-a[i+1]) - abs(a[i-1]-a[i+1]);
maxx = max(maxx,t);
}
// cout<<"***"<<maxx<<"***"<<endl;
}
ll sum = 0;
for(int i = 1;i < n;i ++){
sum += abs(a[i]-a[i+1]);
}
sum -= maxx;
printf("%lld\n",sum);
}
return 0;
}