CF868F题解
先考虑朴素的暴力,设
可以先在外层枚举
考虑整体二分。待转移区间
如何计算
总的复杂度就是
代码:
#include<bits/stdc++.h>
#define ll long long
using namespace std;
ll n,k,a[100005],f[100005],g[100005],cnt[100005],ml,mr,w;
inline void add(ll x){if(x)w+=cnt[a[x]],cnt[a[x]]++;}
inline void del(ll x){if(x)cnt[a[x]]--,w-=cnt[a[x]];}
inline void move(ll l,ll r){
while(mr<r)add(++mr);
while(ml>l)add(--ml);
while(mr>r)del(mr--);
while(ml<l)del(ml++);
}
void solve(ll l,ll r,ll fl,ll fr){
if(fl==fr){
for(ll i=l;i<=r;i++){
move(fl,i);
f[i]=g[fl-1]+w;
}
return ;
}
ll mid=(l+r)>>1,pos,minn=1e16;
for(ll i=fl;i<=min(fr,mid);i++){
move(i,mid);
ll v=g[i-1]+w;
if(v<=minn)minn=v,pos=i;
}
f[mid]=minn;
if(l==r)return ;
solve(l,mid,fl,pos);
solve(mid+1,r,pos,fr);
}
int main(){
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
cin>>n>>k;
for(ll i=1;i<=n;i++){
cin>>a[i];
g[i]=g[i-1]+cnt[a[i]];
cnt[a[i]]++;
}
memset(cnt,0,sizeof(cnt));
w=0;
for(ll i=2;i<=k;i++){
solve(1,n,1,n);
for(ll j=1;j<=n;j++)g[j]=f[j];
}
cout<<g[n];
return 0;
}