【ZJOI2007】仓库建设(斜率优化dp)

设f[i]表示前i个仓库的货物处理完所需的最小花费。
假设第k+1~i个仓库的货物集中在一起,那么只能是都搬到i仓库。
那么此时:

\small f[i]=f[k]+p[k+1]*dis(k+1,i)+p[k+2]*dis(k+2,i)+...+p[i]*dis(i,i)+c[i]
用给的x转化一下:

\small f[i]=f[k]+p[k+1]*(x[i]-x[k+1])+p[k+2]*(x[i]-x[k+2])+...+p[i]*0+c[i]
设sump[i]表示前i个仓库的p之和,可以得到:

\small f[i]=f[k]+(sump[i]-sump[k])*x[i]-x[k+1]*p[k+1]-x[k+2]*p[k+2]-...-x[i]*p[i]+c[i]
\small t[i]=x[1]*p[1]+x[2]*p[2]+...+x[i]*p[i]

那么整个式子就变成了:

\small f[i]=f[k]+(sump[i]-sump[k])*x[i]-(t[i]-t[k])+c[i]
移项,可以得到:

\small f[k]+t[k]=sump[k]*x[i]+f[i]-x[i]*sump[i]+t[i]-c[i]
由于x[i]满足大于0且单调递增,而f[i]要求最小值,所以这里只要单调队列维护一个下凸包即可。

#include
#include
#include
#include
using namespace std;
typedef long long LL;
const int MAXN=1000005;
int N,q[MAXN];
LL f[MAXN],x[MAXN],sump[MAXN],t[MAXN],c[MAXN];

char C;
void scan(int &x)
{
	for(C=getchar();C<'0'||C>'9';C=getchar());
	for(x=0;C>='0'&&C<='9';C=getchar()) x=x*10+C-'0';
}

void scan(LL &x)
{
	for(C=getchar();C<'0'||C>'9';C=getchar());
	for(x=0;C>='0'&&C<='9';C=getchar()) x=x*10+C-'0';
}

int main()
{
	int i;
	LL p;
	scan(N);
	for(i=1;i<=N;i++)
	{
		scan(x[i]);scan(p);scan(c[i]);
		sump[i]=sump[i-1]+p;
		t[i]=t[i-1]+x[i]*p;
	}
	
	memset(f,0x3f,sizeof(f));
	f[0]=0;
	
	int L=1,R=1;
	for(i=1;i<=N;i++)
	{
		while(L

 

你可能感兴趣的:(动态规划)