[ZJOI2007]仓库建设

题面描述

传送门

思路

决策单调性

其实很容易想到方程,

F i = min ⁡ ( F j + c i F_i=\min(F_j+c_i Fi=min(Fj+ci + + + [ j + 1 , i − 1 ] [j+1,i-1] [j+1,i1]的物品运到 i i i的花费)

关键在于如何快速求到 [ j + 1 , i − 1 ] [j+1,i-1] [j+1,i1]的物品运到 i i i的花费

运用前缀和思想,我们将 [ j + 1 , i − 1 ] [j+1,i-1] [j+1,i1]的物品放在原点,运到 i i i的花费为(此时 p p p为物品数的前缀和,下同)

d i s i ∗ ( p i − 1 − p j ) dis_i*(p_{i-1}-p_j) disi(pi1pj)

但是物品 [ j + 1 , i − 1 ] [j+1,i-1] [j+1,i1]并不在原点啊,而是在 [ j + 1 , i − 1 ] [j+1,i-1] [j+1,i1]点上啊,

那么我们需要再来一个前缀和 s s s,来求从原点出发,物品数 j + 1 j+1 j+1到点 j + 1 j+1 j+1的花费,物品数 j + 2 j+2 j+2到点 j + 2 j+2 j+2的花费, ⋯ \cdots ,物品数 i − 1 i-1 i1到点 i − 1 i-1 i1的花费。

那么 [ j + 1 , i − 1 ] [j+1,i-1] [j+1,i1]的物品运到 i i i的花费为

d i s i ∗ ( p i − 1 − p j ) − s i − 1 + s j dis_i*(p_{i-1}-p_j)-s_{i-1}+s_j disi(pi1pj)si1+sj

好了,真正的方程

F i = min ⁡ ( F j + c i + d i s i ∗ ( p i − 1 − p j ) − s i − 1 + s j ) F_i=\min(F_j+c_i+dis_i*(p_{i-1}-p_j)-s_{i-1}+s_j) Fi=min(Fj+ci+disi(pi1pj)si1+sj)

假设有 F j + c i + d i s i ∗ ( p i − 1 − p j ) − s i − 1 + s j ≥ F k + c i + d i s i ∗ ( p i − 1 − p j ) − s i − 1 + s k ( j &lt; k &lt; i ) F_j+c_i+dis_i*(p_{i-1}-p_j)-s_{i-1}+s_j\ge F_k+c_i+dis_i*(p_{i-1}-p_j)-s_{i-1}+s_k(j&lt;k&lt;i) Fj+ci+disi(pi1pj)si1+sjFk+ci+disi(pi1pj)si1+sk(j<k<i)

化简为

F j − d i s i ∗ p j + s j ≥ F k − d i s i ∗ p k + s k F_j-dis_i*p_j+s_j\ge F_k-dis_i*p_k+s_k Fjdisipj+sjFkdisipk+sk

那么对于未来状态 t t t,是否也有 k k k优于 j j j呢?

证明: F j + c t + d i s t ∗ ( p t − 1 − p j ) − s t − 1 + s j ≥ F k + c t + d i s t ∗ ( p t − 1 − p j ) − s t − 1 + s k ( j &lt; k &lt; i &lt; t ) F_j+c_t+dis_t*(p_{t-1}-p_j)-s_{t-1}+s_j\ge F_k+c_t+dis_t*(p_{t-1}-p_j)-s_{t-1}+s_k(j&lt;k&lt;i&lt;t) Fj+ct+dist(pt1pj)st1+sjFk+ct+dist(pt1pj)st1+sk(j<k<i<t)

现将原式化简

F j − d i s t ∗ p j + s j , F k − d i s t ∗ p k + s k F_j-dis_t*p_j+s_j,F_k-dis_t*p_k+s_k Fjdistpj+sj,Fkdistpk+sk

一定有 d i s t &gt; d i s i dis_t&gt;dis_i dist>disi,则 d i s t = d i s i + v a l ( v a l &gt; 0 ) dis_t=dis_i+val(val&gt;0) dist=disi+val(val>0)

因此

F j − ( d i s i + v a l ) ∗ p j + s j , F k − ( d i s i + v a l ) ∗ p k + s k F_j-(dis_i+val)*p_j+s_j,F_k-(dis_i+val)*p_k+s_k Fj(disi+val)pj+sj,Fk(disi+val)pk+sk

F j − d i s i ∗ p j − v a l ∗ p j + s j , F k − d i s i ∗ p j − v a l ∗ p k + s k F_j-dis_i*p_j-val*p_j+s_j,F_k-dis_i*p_j-val*p_k+s_k Fjdisipjvalpj+sj,Fkdisipjvalpk+sk

将①代入②,证明 − v a l ∗ p j ≥ − v a l ∗ p k -val*p_j\ge-val*p_k valpjvalpk即可

v a l ∗ p j ≤ v a l ∗ p k val*p_j\le val*p_k valpjvalpk

p j ≤ p k p_j\le p_k pjpk

p k &gt; p j p_k&gt;p_j pk>pj得证。

因此决策单调性得出

( F j + c i + d i s i ∗ ( p i − 1 − p j ) − s i − 1 + s j ≥ F k + c i + d i s i ∗ ( p i − 1 − p j ) − s i − 1 + s k ( j &lt; k &lt; i ) F_j+c_i+dis_i*(p_{i-1}-p_j)-s_{i-1}+s_j\ge F_k+c_i+dis_i*(p_{i-1}-p_j)-s_{i-1}+s_k(j&lt;k&lt;i) Fj+ci+disi(pi1pj)si1+sjFk+ci+disi(pi1pj)si1+sk(j<k<i)时, k k k优于 j j j j j j没有用了)

踢队头

我们用上述①式来求解:

F j − d i s i ∗ p j + s j ≥ F k − d i s i ∗ p k + s k F_j-dis_i*p_j+s_j\ge F_k-dis_i*p_k+s_k Fjdisipj+sjFkdisipk+sk

F j − F k + s j − s k ≥ d i s i ∗ ( p j − p k ) F_j-F_k+s_j-s_k\ge dis_i*(p_j-p_k) FjFk+sjskdisi(pjpk)

p j &lt; p k p_j&lt;p_k pj<pk

F j − F k + s j − s k p j − p k ≤ d i s i \frac{F_j-F_k+s_j-s_k}{p_j-p_k}\le dis_i pjpkFjFk+sjskdisi

时, k k k优于 j j j.

c a l c ( j , k ) calc(j,k) calc(j,k)表示 F j − F k + s j − s k p j − p k \frac{F_j-F_k+s_j-s_k}{p_j-p_k} pjpkFjFk+sjsk,就有

c a l c ( j , k ) ≤ d i s i calc(j,k)\le dis_i calc(j,k)disi

如果 c a l c ( q h e a d , q h e a d + 1 ) ≤ d i s i calc(q_{head},q_{head+1})\le dis_i calc(qhead,qhead+1)disi

则证明 q h e a d + 1 q_{head+1} qhead+1优于 q h e a d q_{head} qhead

踢队尾

我们首先一定要确定 i i i这个状态,要优于 q t a i l q_{tail} qtail

要维护的队列由于 q t a i l − 1 q_{tail-1} qtail1一定优于 q t a i l q_{tail} qtail

现有一个标准值 d i s t ( t a i l &lt; t ) dis_t(tail&lt;t) dist(tail<t)

c a l c ( q t a i l − 1 , q t a i l ) ≥ d i s t calc(q_{tail-1},q_{tail)}\ge dis_t calc(qtail1,qtail)dist

如果 q t a i l q_{tail} qtail要优于 i i i

c a l c ( q t a i l , i ) ≥ c a l c ( q t a i l − 1 , q t a i l ) calc(q_{tail},i)\ge calc(q_{tail-1},q_{tail}) calc(qtail,i)calc(qtail1,qtail)

才能确保 q t a i l q_{tail} qtail优于 i i i

反之,当 c a l c ( q t a i l , i ) ≤ c a l c ( q t a i l − 1 , q t a i l ) calc(q_{tail},i)\le calc(q_{tail-1},q_{tail}) calc(qtail,i)calc(qtail1,qtail)时,需要删去队尾。

貌似就没了哦。

AC code

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cstdlib>
#include<cmath>
#include<iostream>
#define gc getchar()
#define ll long long 
using namespace std;
const int N=1e6+10;
inline void qr(ll &x)
{
	x=0;int f=1;char c=gc;
	while(c<'0'||c>'9'){if(c=='-')f=-1;c=gc;}
	while(c>='0'&&c<='9'){x=x*10+(c^48);c=gc;}
	x*=f;
}
void qw(ll x)
{
	if(x<0)x=-x,putchar('-');
	if(x/10)qw(x/10);
	putchar(x%10+48);
}
ll s[N],p[N],c[N],f[N],dis[N];
inline double calc(int j,int k)
{
	return (f[j]-f[k]+s[j]-s[k])/(double)(p[j]-p[k]);
}
int q[N],l,r,n;
int main()
{
	scanf("%d",&n);
	for(int i=1;i<=n;i++)qr(dis[i]),qr(p[i]),qr(c[i]);
	for(int i=1;i<=n;i++)
	{
		s[i]=s[i-1]+dis[i]*p[i];
		p[i]+=p[i-1];
	}
	l=1;r=1;q[1]=0;
	for(int i=1;i<=n;i++)
	{
		while(l<r&&calc(q[l],q[l+1])<=1.0*dis[i])++l;
		f[i]=f[q[l]]+(p[i-1]-p[q[l]])*dis[i]-(s[i-1]-s[q[l]])+c[i];
		while(l<r&&calc(q[r],i)<=calc(q[r-1],q[r]))--r;
		q[++r]=i;
	}
	qw(f[n]);puts("");
	return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值