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...

posted @ 2020-12-06 11:35  ullio  阅读(78)  评论(0编辑  收藏  举报