题意
给定数组 a a a,每次可以把后缀加一或减一,问最少操作次数
而且,你有一次改变某个 a i a_i ai的机会,可以改成任意数字
先考虑不改变某个 a i a_i ai时的答案
由于最后所有数字都要变成一样,所以当后 n − 1 n-1 n−1个数字变得和 a 1 a_1 a1一样时就不需要操作了
证明
如果后 n − 1 n-1 n−1个数字不是变成 a 1 a_1 a1,对 [ 1 , n ] [1,n] [1,n]同时加减多少次也无法满足条件
那么让 [ 2 , n ] [2,n] [2,n]的数字都变成 a 1 a_1 a1,前提是 [ 3 , n ] [3,n] [3,n]的数都变成 a 2 a_2 a2,否则也无法满足要求
那么不改变 a i a_i ai的话,答案就是 ∑ i = 1 n − 1 a b s ( a [ i ] − a [ i + 1 ] ) \sum\limits_{i=1}^{n-1}abs(a[i]-a[i+1]) i=1∑n−1abs(a[i]−a[i+1])
因为后缀 [ i + 1 , n ] [i+1,n] [i+1,n]变得一样了,需要操作 a b s ( a [ i ] − a [ i + 1 ] ) abs(a[i]-a[i+1]) abs(a[i]−a[i+1])次变得和 a i a_i ai一样
如果改变 a i + 1 a_{i+1} ai+1的值,肯定是改成 a i + 2 a_{i+2} ai+2最优秀
这样原操作需要 a b s ( a [ i + 1 ] − a [ i + 2 ] ) + a b s ( a [ i ] − a [ i + 1 ] ) abs( a[i+1]-a[i+2] )+abs( a[i]-a[i+1] ) abs(a[i+1]−a[i+2])+abs(a[i]−a[i+1])
现在只需要 a b s ( a [ i ] − a [ i + 2 ] ) abs( a[i]-a[i+2] ) abs(a[i]−a[i+2])
就省掉了 a b s ( a [ i + 1 ] − a [ i + 2 ] ) + a b s ( a [ i ] − a [ i + 1 ] ) − a b s ( a [ i ] − a [ i + 2 ] ) abs( a[i+1]-a[i+2] )+abs( a[i]-a[i+1] )-abs( a[i]-a[i+2] ) abs(a[i+1]−a[i+2])+abs(a[i]−a[i+1])−abs(a[i]−a[i+2])次
取这个省去操作的 m a x max max即可
当然 a 1 a_1 a1也可以改成 a 2 a_2 a2,然后 a n a_n an也可以改成 a n − 1 a_{n-1} an−1
对答案取 m i n min min即可
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int maxn=3e5+10;
const int mod = 998244353,G=3,Gi = 332748118;
int n,m,a[maxn],b[maxn];
signed main()
{
int t;
cin >> t;
while( t-- )
{
cin >> n;
for(int i=1;i<=n;i++) cin >> a[i];
int temp = 0,kl=0,ans1=0,ans2=0;
for(int i=n-1;i>=1;i--)
{
temp += abs( a[i]-a[i+1] );
if( i+2<=n )
kl = max( kl,abs( a[i+1]-a[i+2] )+abs( a[i]-a[i+1] )-abs( a[i]-a[i+2] ) );
}
for(int i=n-2;i>=1;i--) ans1 += abs( a[i]-a[i+1] );
for(int i=n-1;i>=2;i--) ans2 += abs( a[i]-a[i+1] );
cout << min( min(ans1,ans2),temp-kl ) << endl;
}
}