Estimation[优先队列+DP]

本文介绍了一种解决区间划分问题的算法,通过动态规划求解将区间[1, i]分成j段的最小花费。利用优先队列动态维护区间的前半部分和后半部分,以快速计算区间的总花费,复杂度为O(n^2*log(n)+n^2*k)。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

传送门

首先f[i][j] 表示1--i 区间分成j段的最小花费,w[i][j]表示区间i--j的花费

f[i][j]=min(f[i][j],f[x][j-1]+w[x+1][i])

现在是如何快速求w[i][j]的问题

首先知道B因取中位数

其次发现w[i][j] = val[后半部分] - val[前半部分]

用两个优先队列动态维护前一半和后一半就好了

复杂度O(n^2*log(n) + n^2*k)


#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#define N 2005
#define K 30
using namespace std;
int f[N][K],n,k,a[N],w[N][N];
int main(){
	while(scanf("%d%d",&n,&k) && (n+k)!=0){	
		for(int i=1;i<=n;i++){
			scanf("%d",&a[i]);
		}
		for(int i=1;i<=n;i++){
			priority_queue<int> pre;
           	priority_queue<int,vector<int>,greater<int> > suf;
           	int now=0;
			for(int j=i;j<=n;j++){
           		if(suf.empty()||a[j]>=suf.top()) suf.push(a[j]),now+=a[j];
           		else pre.push(a[j]),now-=a[j];
           		int x1=(j-i+1)>>1,x2=j-i+1-x1;
           		if(pre.size()>x1) suf.push(pre.top()),now+=pre.top()*2,pre.pop();
           		if(suf.size()>x2) pre.push(suf.top()),now-=suf.top()*2,suf.pop();
           		if(x1==x2) w[i][j]=now;
           		else w[i][j]=now-suf.top();
			}
		}
		memset(f,127,sizeof(f));
		for(int i=1;i<=n;i++) f[i][1]=w[1][i];
		for(int i=1;i<=n;i++)
			for(int j=2;j<=k;j++)
				for(int x=1;x<i;x++)
					f[i][j]=min(f[i][j],f[x][j-1]+w[x+1][i]);
		printf("%d\n",f[n][k]);
	}return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

FSYo

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值