题解:CF2085F2 Serval and Colorful Array (Hard Version)
题意
给定一个序列,可以交换相邻元素,问至少交换多少次使得存在一个子区间是一个
思路
由 F1 的暴力做法得知,可以钦定一个位置为中心,其他期望出现在区间中的数向中间靠拢,计算过程就是统计每种数出现在中心的左或右的最近位置,看左右两边去哪个更优,最后减去多余的移动即可(就是不需要都移到中心位置,一个接一个就行)。
考虑如何优化这一过程。先对每种数分开观察,会发现每次的变化量的绝对值
实现简洁,代码如下
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int maxn=4e5+10;
int n,k,s,d,ans;
int a[maxn],lst[maxn],sum[maxn];
signed main()
{
int t;
cin>>t;
while(t--)
{
s=0,ans=1e18;
cin>>n>>k;
for(int i=1;i<=n;i++) lst[i]=sum[i]=0;
for(int i=1;i<=n;i++)
{
cin>>a[i];
if(!lst[a[i]]) s+=i-1;
else
{
int pre=lst[a[i]],mid=(pre+i)/2;
if((pre+i)&1) sum[mid]--,sum[mid+1]--;
else sum[mid]-=2;
}
sum[i]+=2;
lst[a[i]]=i;
}
d=-k;
for(int i=1;i<=n;i++)
{
ans=min(ans,s);
d+=sum[i],s+=d;
}
for(int i=1;i<=k;i++) ans-=abs(i-(k+1)/2);
cout<<ans<<endl;
}
}