D. Not Alone
D. Not Alone
处理一:\(b_i = b_{(i+m-2)\bmod m\;+1}\), 或 \(b_i = b_{i\bmod m\;+1}\)
考虑将环分成多块处理,保证块长大于 \(1\)。
处理二:\(\sum_{i=1}^n |b_i - a_i|\)
由于对于 \(a_i\),操作只有 \(+1\) 和 \(-1\),对于每个块,最小的操作数就是将其变成中位数(中位数定理)。
那么划分成多块操作会超时,我们考虑会不会有更好的策略:
观察一个块内有 \(4\) 个元素:可以拆成两个 \(2\) 个元素的块,这样总会使得结果变小。
同理最终把块拆成 \(2\) 块和 \(3\) 块总会使得答案最好。
如果长度为 \(2\) 和 \(3\),\(cost\) 就是最大值 \(-\) 最小值。
处理三:环
将数组循环移位操作几次,然后在开头断开,断环成链进行计算。
点击查看代码
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
const ll INF = 1000000000000000005;
ll cost(ll x, ll y){
return max(x, y) - min(x, y);
}
ll cost(ll x, ll y, ll z){
return max({x, y, z}) - min({x, y, z});
}
void solve(){
int n;
cin >> n;
vector<int> a(n + 1);
for(int i = 1;i <= n;i++){
cin >> a[i];
}
auto f = [&]() -> ll{
vector<ll> dp(n + 1, 0);
dp[0] = 0;
dp[1] = INF;
for(int i = 2;i <= n;i++){
dp[i] = dp[i - 2] + cost(a[i - 1], a[i]);
if(i >= 3){
dp[i] = min(dp[i], dp[i - 3] + cost(a[i - 2], a[i - 1], a[i]));
}
}
return dp[n];
};
ll ans = INF;
for(int cyc = 0; cyc < 4;cyc++){
ans = min(ans, f());
for(int i = 2;i <= n;i++){
swap(a[i], a[i - 1]);
}
}
cout << ans << "\n";
}
int main(){
//ios::sync_with_stdio(false);
//cin.tie(nullptr), cout.tie(nullptr);
int T = 1;
cin >> T;
while(T--){
solve();
}
return 0;
}