1. 程式人生 > 實用技巧 >Codeforces Round #688 (Div. 2) B

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