专栏文章
CF868F题解
CF868F题解参与者 1已保存评论 1
文章操作
快速查看文章及其快照的属性,并进行相关操作。
- 当前评论
- 1 条
- 当前快照
- 1 份
- 快照标识符
- @mio8rxxi
- 此快照首次捕获于
- 2025/12/02 15:13 3 个月前
- 此快照最后确认于
- 2025/12/02 15:13 3 个月前
先考虑朴素的暴力,设 表示前 个数划分为 段的最小代价,有 ,其中, 表示 中相同元素的对数。
可以先在外层枚举 ,考虑如何处理 的转移。记数组 为枚举上一个 时的 。假设有转移决策点 和 ,假设 从 转移,则有 ,由于区间 中的数的种类不少于区间 ,所以 ,即 ,也就是说,对于大于 的点,都不会从 转移,即 具有决策单调性。
考虑整体二分。待转移区间 ,和决策点区间 ,对于 的中点 ,暴力的找出其对应的决策点 ,然后递归处理即可。
如何计算 ,可以使用类似莫队的东西去维护,均摊下来复杂度是 的。
总的复杂度就是 的。
代码:
CPP#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;
}
相关推荐
评论
共 1 条评论,欢迎与作者交流。
正在加载评论...