[bzoj1096][ZJOI2007]仓库建设

[bzoj1096][ZJOI2007]仓库建设

标签: DP 斜率优化


题目链接

题解

首先要秒写出dp方程

\[dp[i]=max(dp[j]+\sum_{k=j+1}^i p[k](x[i]-x[k])) \]

\[令sp[n]=\sum_{i=1}^n p[i],s[n]=\sum_{i=1}^n x[i]×p[i] \]

\[方程可简写为dp[i]=max(dp[j]+x[i]×(sp[i]-sp[j])-(s[i]-s[j])) \]

\(设i从j转移过来,取k满足j< k\)

\[dp[j]+x[i](sp[i]-sp[j])-(s[i]-s[j])< dp[k]+x[i](sp[i]-sp[j])-(s[i]-s[k]) \]

\[化简,得dp[j]-dp[k]+s[j]-s[k]< x[i](sp[j]-sp[k]) \]

\[\frac{dp[j]-dp[k]+s[j]-s[k]}{sp[j]-sp[k]}>x[i] \]

斜率优化即可。

Code

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<queue>
#include<stack>
#include<set>
#include<map>
using namespace std;
#define ll long long
#define REP(i,a,b) for(int i=(a),_end_=(b);i<=_end_;i++)
#define DREP(i,a,b) for(int i=(a),_end_=(b);i>=_end_;i--)
#define EREP(i,a) for(int i=start[(a)];i;i=e[i].next)
inline int read()
{
	int sum=0,p=1;char ch=getchar();
	while(!(('0'<=ch && ch<='9') || ch=='-'))ch=getchar();
	if(ch=='-')p=-1,ch=getchar();
	while('0'<=ch && ch<='9')sum=sum*10+ch-48,ch=getchar();
	return sum*p;
}

const int maxn=1e6+20;

int n;
ll x[maxn],sp[maxn],s[maxn],c[maxn],p[maxn];
ll dp[maxn];

void init()
{
	n=read();
	REP(i,1,n)
	{
		x[i]=read();p[i]=read();c[i]=read();
		sp[i]=sp[i-1]+p[i];
		s[i]=s[i-1]+x[i]*p[i];
	}
}

double count(int j,int k)
{
	return (double)(dp[j]-dp[k]+s[j]-s[k])/(sp[j]-sp[k]);
}

int q[maxn],head,tail;

void doing()
{
	head=1;tail=1;
	REP(i,1,n)
	{
		while(head<tail && count(q[head],q[head+1])<x[i])head++;
		int xx=q[head];
		dp[i]=dp[xx]+x[i]*(sp[i]-sp[xx])-s[i]+s[xx]+c[i];
		while(head<tail && count(q[tail-1],q[tail])>count(q[tail],i))tail--;
		q[++tail]=i;
	}
	printf("%lld\n",dp[n]);
}

int main()
{
	freopen("factory.in","r",stdin);
	freopen("factory.out","w",stdout);
	init();
	doing();
	return 0;
}


posted @ 2017-10-23 17:16  Deadecho  阅读(55)  评论(0编辑  收藏