把博客园图标替换成自己的图标
把博客园图标替换成自己的图标end

CF868F Yet Another Minimization Problem

题面传送门
显然有一眼\(O(n^2k)\)的dp:设\(dp_{i,j}\)为分了\(i\)段,分到第\(j\)个时的最小值。
那么可以\(O(n)\)暴力转移。
因为每种颜色相互独立,所以我们对每种颜色分别考虑。
如果\([i,j]\)中有\(x\)个,\([i',j']\)中有\(y\)个,\([i,j']\)中有\(z\)个,那么\([i',j]\)里有\(x+y-z\)个。
展开一下就可以发现这个满足决策单调性。
又因为这个不从自己转移,所以可以用分治法解决。
转移时像莫队一样暴力移动即可。
时间复杂度\(O(nklogn)\)
code:

#include<cstdio>
#include<cstring> 
#define N 100000
#define I inline
#define re register
#define ll long long
#define min(a,b) ((a)<(b)?(a):(b))
#define max(a,b) ((a)>(b)?(a):(b)) 
using namespace std;
int n,k,a[N+5],f[N+5],ls=1,rs;ll w,g[N+5],dp[N+5]; 
I void get(int l,int r){
	while(ls>l) w+=f[a[--ls]]++;
	while(rs<r) w+=f[a[++rs]]++;
	while(ls<l) w-=--f[a[ls++]];
	while(rs>r) w-=--f[a[rs--]];
}
I void solve(int l,int r,int x,int y){
	if(x>y) return;int mid=x+y>>1,i,p=mid,nowl=ls,nowr=rs;
	for(i=min(mid,r);i>=l;i--) get(i,mid),dp[mid]>g[i-1]+w&&(dp[mid]=g[i-1]+w,p=i);
	solve(l,p,x,mid-1);solve(p,r,mid+1,y);get(nowl,nowr);
}
int main(){
	freopen("1.in","r",stdin);
	re int i,j;scanf("%d%d",&n,&k);memset(dp,0x3f,sizeof(dp));dp[0]=0;
	for(i=1;i<=n;i++) scanf("%d",&a[i]);
	for(i=1;i<=k;i++){
		for(j=1;j<=n;j++) g[j]=dp[j];solve(1,n,1,n);
	}
	printf("%lld\n",dp[n]);
}
posted @ 2021-04-24 08:32  275307894a  阅读(48)  评论(0编辑  收藏  举报
浏览器标题切换
浏览器标题切换end