题面描述
思路
决策单调性
其实很容易想到方程,
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,i−1]的物品运到 i i i的花费)
关键在于如何快速求到 [ j + 1 , i − 1 ] [j+1,i-1] [j+1,i−1]的物品运到 i i i的花费
运用前缀和思想,我们将 [ j + 1 , i − 1 ] [j+1,i-1] [j+1,i−1]的物品放在原点,运到 i i i的花费为(此时 p p p为物品数的前缀和,下同)
d i s i ∗ ( p i − 1 − p j ) dis_i*(p_{i-1}-p_j) disi∗(pi−1−pj)
但是物品 [ j + 1 , i − 1 ] [j+1,i-1] [j+1,i−1]并不在原点啊,而是在 [ j + 1 , i − 1 ] [j+1,i-1] [j+1,i−1]点上啊,
那么我们需要再来一个前缀和 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 i−1到点 i − 1 i-1 i−1的花费。
那么 [ j + 1 , i − 1 ] [j+1,i-1] [j+1,i−1]的物品运到 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∗(pi−1−pj)−si−1+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∗(pi−1−pj)−si−1+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 < k < 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<k<i) Fj+ci+disi∗(pi−1−pj)−si−1+sj≥Fk+ci+disi∗(pi−1−pj)−si−1+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 Fj−disi∗pj+sj≥Fk−disi∗pk+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 < k < i < 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<k<i<t) Fj+ct+dist∗(pt−1−pj)−st−1+sj≥Fk+ct+dist∗(pt−1−pj)−st−1+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 Fj−dist∗pj+sj,Fk−dist∗pk+sk
一定有 d i s t > d i s i dis_t>dis_i dist>disi,则 d i s t = d i s i + v a l ( v a l > 0 ) dis_t=dis_i+val(val>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 Fj−disi∗pj−val∗pj+sj,Fk−disi∗pj−val∗pk+sk
②
将①代入②,证明 − v a l ∗ p j ≥ − v a l ∗ p k -val*p_j\ge-val*p_k −val∗pj≥−val∗pk即可
v a l ∗ p j ≤ v a l ∗ p k val*p_j\le val*p_k val∗pj≤val∗pk
p j ≤ p k p_j\le p_k pj≤pk
由 p k > p j p_k>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 < k < 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<k<i) Fj+ci+disi∗(pi−1−pj)−si−1+sj≥Fk+ci+disi∗(pi−1−pj)−si−1+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 Fj−disi∗pj+sj≥Fk−disi∗pk+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) Fj−Fk+sj−sk≥disi∗(pj−pk)
由 p j < p k p_j<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 pj−pkFj−Fk+sj−sk≤disi
时, 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} pj−pkFj−Fk+sj−sk,就有
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} qtail−1一定优于 q t a i l q_{tail} qtail
现有一个标准值 d i s t ( t a i l < t ) dis_t(tail<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(qtail−1,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(qtail−1,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(qtail−1,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;
}