传送门
写在前面:前来报道的学弟
思路:这是学习斜率优化后完全自己独立处理出的第一个题吧,感觉自己还是太弱,这么就初步理解斜率优化。
先推转移方程,这个还是比较好弄得
f[i]=c[i]+min(f[j]+∑ik=j+1p[k]∗(s[i]−s[k]))
看似是一个
O(n3)
,但我们把sigma里的东西拆开,处理前缀和
sum1[i]=∑ij=1p[j]∗s[j]
sum2[i]=∑ij=1p[j]
那么转移就是
f[i]=c[i]+min(f[j]+s[i]∗(sum2[i]−sum2[j])−(sum1[i]−sum1[j]))
O(n2)
可以得20分
正解是
O(n)
的
假设x>y且由x比y转移更优
然后一顿化简,得到
(f[x]−f[y]+sum1[x]−sum1[y])/(sum2[x]−sum2[y])<s[i]
接下来就代码了
注意:
有符号整型把我吓了一跳,还以为有负数个货物……
代码:
#include<bits/stdc++.h>
#define LL long long
#define M 1000002
using namespace std;
int n,head=1,tail=1;
int s[M],c[M],p[M],q[M];
LL f[M],sum1[M],sum2[M];
int in()
{
int t=0,f=1;char ch=getchar();
while (ch>'9'||ch<'0')
{
if (ch=='-') f=-1;
ch=getchar();
}
while (ch>='0'&&ch<='9') t=(t<<3)+(t<<1)+ch-'0',ch=getchar();
return f*t;
}
double Get(int x,int y)
{
return (double)(f[x]-f[y]+(sum1[x]-sum1[y]))/(double)(sum2[x]-sum2[y]);
}
main()
{
n=in();
for (int i=1;i<=n;i++)
s[i]=in(),p[i]=in(),c[i]=in(),
sum1[i]=sum1[i-1]+(LL)p[i]*s[i],
sum2[i]=sum2[i-1]+p[i];
for (int i=1;i<=n;i++)
{
while (head<tail&&Get(q[head+1],q[head])<(double)s[i]) head++;
f[i]=f[q[head]]+c[i]+s[i]*(sum2[i]-sum2[q[head]])-(sum1[i]-sum1[q[head]]);
while (head<tail&&Get(i,q[tail])<Get(q[tail],q[tail-1])) tail--;
q[++tail]=i;
}
printf("%lld",f[n]);
}