洛谷P4360[CEOI2004]锯木厂选址

本文详细解析洛谷P4360锯木厂问题的解决方案,采用双DP策略,通过预处理求解前缀和与优化后的下凸包结构,运用单调队列维护最优解,实现复杂锯木厂布局问题的有效求解。

https://www.luogu.com.cn/problem/P4360

做两遍dp,dp[k][i]表示前i个位置放k个锯木厂的最小值

先把整个顺序反过来,那么0的位置就是山脚的锯木厂

设sum[i],f[i]是sum[i]w[i]前缀和,f2[i]是w[i]的前缀和

dp[1][i]=f[i]-f[k]-sum[k+1](f2[i]-f2[k])+dp[0][k]

展开成f2[k]sum[k+1]-f[k]+dp[0][k]=f2[i]sum[k+1]+dp[1][i]-f[i]

k=f2[i]递增,sum[k+1]递增,希望截距dp[1][i]-f[i]尽可能小

画图分析得用单调队列维护一个下凸包

#include<bits/stdc++.h>
using namespace std;

const int maxl=2e4+10;
typedef long long ll;

int n;
ll w[maxl],d[maxl],sum[maxl],f[maxl],f2[maxl];
ll dp[3][maxl];
struct node
{
	ll x,y;
}s[maxl];

inline void prework()
{
	scanf("%d",&n);
	for(int i=n;i>=1;i--)
		scanf("%lld%lld",&w[i],&d[i]);
	for(int i=1;i<=n;i++)
	{
		sum[i]=sum[i-1]+d[i];
		f[i]=f[i-1]+w[i]*sum[i];
		f2[i]=f2[i-1]+w[i];
		dp[0][i]=f[i];
	}
}

inline ll calc(ll k,int id)
{
	return s[id].y-k*s[id].x;
}

inline bool cmpk(node a,node b,node c)
{
	return 1.0*(b.y-a.y)*(c.x-b.x)>=1.0*(c.y-b.y)*(b.x-a.x);
}

inline void solv(int k)
{
	int head=1,tail=0;
	node d=node{sum[1],0};
	s[++tail]=d;
	for(int i=1;i<=n;i++)
	{
		while(head<tail && calc(f2[i],head)>=calc(f2[i],head+1))
			head++;
		dp[k][i]=calc(f2[i],head)+f[i];
		d=node{sum[i+1],f2[i]*sum[i+1]-f[i]+dp[k-1][i]};
		while(head<tail && cmpk(s[tail-1],s[tail],d))
			tail--;
		s[++tail]=d; 
	}
}

inline void mainwork()
{
	for(int k=1;k<=2;k++)
		solv(k);
}

inline void print()
{
	printf("%lld",dp[2][n]);
}

int main()
{
	prework();
	mainwork();
	print();
	return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值