Not Alone:唐题。
容易将题意转化为:环上的每一个颜色段长度都 \(\ge 2\),求最小操作数。
再考虑一个 \(O(n^2\log n)\) 的暴力,定义 \(dp_i\) 表示以 \(i\) 结尾的最小操作数,然后枚举前一个转移点 \(j\)。继续考虑如何计算 \([j + 1, i]\) 的最小操作数,容易注意到这是个经典的绝对值不等式,于是取中位数即可。
感性地发现一大段相等的数不如拆成几个小段的区间。于是从 \(n = 2, 3,4\) 的情况入手,发现:
- \(n = 2\) 时,只能全部相等。
- \(n = 3\) 时,只能全部相等。
- \(n = 4\) 时,\([a_1, a_2, a_3, a_4]\) 分成 \([a_1, a_2],[a_3, a_4]\) 比直接不分段更优秀,因为分段时的代价就是 \(|a_2 - a_1| + |a_4 - a_3|\),不分段的时候,分类讨论中位数的位置发现最小值才是 \(|a_2 - a_1| + |a_4 - a_3|\),甚至有可能比它更大。因此不分段一定不优。
- \(n = 5, 6, 7, \cdots\) 时,类似 \(n = 4\),考虑数学归纳法,发现分成若干个长度为 \(2, 3\) 的段一定最优。
于是线性 DP 求解最小方案即可。
拓展到环上,破环为链复杂度会爆炸,所以只需要分类讨论首尾相接处的情况即可。详见代码,时间复杂度 \(O(n)\)。
#include <bits/stdc++.h>
#define fi first
#define se second
#define eb(x) emplace_back(x)
#define pb(x) push_back(x)
#define lc(x) (tr[x].ls)
#define rc(x) (tr[x].rs)
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef long double ldb;
using pi = pair<int, int>;
const int N = 400005;
const ll inf = 0x3f3f3f3f3f3f3f3f;
ll n, a[N], ans, res, dp[N];
ll work(int l, int r)
{dp[l - 1] = 0;for(int i = l; i <= r; i++){dp[i] = inf;if(i == l) continue;// 2dp[i] = min(dp[i], dp[i - 2] + abs(a[i] - a[i - 1]));// 3if(i == l + 1) continue;int mx = max(a[i], max(a[i - 1], a[i - 2])), mn = min(a[i], min(a[i - 1], a[i - 2]));int md = (a[i] ^ a[i - 1] ^ a[i - 2] ^ mx ^ mn);dp[i] = min(dp[i], dp[i - 3] + mx - md + md - mn);}return dp[r];
}
void solve()
{cin >> n;ans = inf;for(int i = 1; i <= n; i++)cin >> a[i];// 0 + 0ans = min(ans, work(1, n));// 1 + 1if(n > 3)ans = min(ans, work(2, n - 1) + abs(a[1] - a[n]));// 1 + 2if(n > 4){int mx = max(a[1], max(a[n], a[n - 1])), mn = min(a[1], min(a[n - 1], a[n]));int md = (a[1] ^ a[n - 1] ^ a[n] ^ mx ^ mn);ans = min(ans, work(2, n - 2) + mx - md + md - mn);}// 2 + 1if(n > 4){int mx = max(a[1], max(a[n], a[2])), mn = min(a[1], min(a[2], a[n]));int md = (a[1] ^ a[2] ^ a[n] ^ mx ^ mn);ans = min(ans, work(3, n - 1) + mx - md + md - mn);}cout << ans << "\n";
}
int main()
{//freopen("sample.in", "r", stdin);//freopen("sample.out", "w", stdout);ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);int t;cin >> t;while(t--) solve();return 0;
}