Codeforces Round #688 (Div. 2) B
Codeforces Round #688 (Div. 2) B
大意
给定一个长为 \(n\) 的数组 \(a\) ,每次可以选定一个位置 \(x\) ,将 \(a_x\sim a_n\) 同时 \(\pm1\) ,问:
如果你可以任选一个位置改成任意你想要的数字,那么·最少多少次操作可以让数组各项相同。
思路
首先任选一个位置修改本质上就是删除一个位置,也就是不用再考虑那个位置。
先考虑没有删除操作时我们该怎么做。
首先,容易发现数组最后必须要等于 \(a_1\) ,因为修改过程中,任意包含在修改范围内的 \(a_i-a_{i+1}\) 的值是不会改变的。
其次,修改顺序并不会影响结果,修改本质是区间加减。
所以,我们假设最优答案的修改顺序是从区间大的到区间小的,即每一次修改选取的下标都要大于等于上一次选取的下标。
那么当某次修改后 \(a_k=a_1\) 时,不难发现 \(a_k-a_{k+1}\) 并没有发生变化。
当经过修改后 \(a_{k+1} = a_1\) 时 \(a_{k+1}-a_{k+2}\) 也没有发生变化。
综上,容易得出在没有删除时总修改次数为 \(\Sigma|a_i-a_{i+1}|\)
现在考虑删除,不难发现当我们删除了 \(a_i\) 后,仅仅改变了 \(a_{i-1}\) 到 \(a_{i+1}\) 的过程,改变量为 \(|a_i-a_{i-1}|+|a_i-a_{i+1}|-|a_{i-1}-a_{i+1}|\)
显然改变量恒大于零。
考虑删除两边,改变量分别为 \(|a_1-a_2|\) 和 \(|a_n-a_{n-1}|\)
记录之中的最大值,最后减去即可
代码
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
using namespace std;
#define ll long long
#define ull unsigned long long
#define cint const int&
#define Pi acos(-1)
const int mod = 998244353;
const int inf_int = 0x7fffffff;
const ll inf_ll = 0x7fffffffffffffff;
const double ept = 1e-9;
int t, n;
ll a[200200];
int main() {
cin >> t;
while(t--) {
cin >> n;
for(int i=1; i<=n; i++) cin >> a[i];
ll tmp=0, mx=0;
for(int i=1; i<=n; i++) {
if(i!=1) tmp += abs(a[i]-a[i-1]);
if(i==1) mx = max(mx, abs(a[1]-a[2]));
else if (i==n) mx = max(mx, abs(a[n]-a[n-1]));
else mx = max(mx, abs(a[i]-a[i-1])+abs(a[i]-a[i+1])-abs(a[i-1]-a[i+1]));
}
cout << tmp-mx << endl;
}
return 0;
}
30min...