我们用sum[i]表示前i个工厂的产品数之和,b[i]表示x[i]*p[i]的前缀和,因此第j+1~i个工厂的产品运到第i个工厂的代价就是
(sum[i]-sum[j])*x[i]-(b[i]-b[j])+ci[i]
最后f[i]的状态转移方程即为:
f[i]=f[j]+(sum[i]-sum[j])*xi[i]-(b[i]-b[j])+ci[i]
斜率式的推导过程就不写了,最后可以化成:
(f[j]+b[j]-f[k]-b[k])/(sum[j]-sum[k])<xi[i]-ci[i](k<j<i)
//然而刚开始最后的那个加号写成乘号导致WA了两次,要注意队列的q[0]=0(不是1!!!),还是要细心吧。
代码:
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 typedef long long LL; 5 const int maxn=1000010; 6 using namespace std; 7 LL xi[maxn],pi[maxn],ci[maxn],sum[maxn],b[maxn],f[maxn],q[maxn]; 8 inline LL read() 9 { 10 LL anss=0,f=1;char c=getchar(); 11 while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();} 12 while(c>='0'&&c<='9'){anss=anss*10+c-48;c=getchar();} 13 return anss*f; 14 } 15 inline double cal(LL a,LL bb) 16 { 17 return 1.0*(f[a]+b[a]-f[bb]-b[bb])/(sum[a]-sum[bb]); 18 } 19 int main() 20 { 21 int n; 22 n=read(); 23 sum[0]=0;b[0]=0; 24 for(int i=1;i<=n;i++){ 25 xi[i]=read();pi[i]=read();ci[i]=read(); 26 sum[i]=sum[i-1]+pi[i]; 27 b[i]=b[i-1]+xi[i]*pi[i]; 28 } 29 int h=0,t=1;q[0]=0;f[0]=0; 30 for(int i=1;i<=n;i++){ 31 while(h<t-1&&cal(q[h],q[h+1])<xi[i])h++; 32 f[i]=f[q[h]]+(sum[i]-sum[q[h]])*xi[i]-(b[i]-b[q[h]])+ci[i]; 33 while(h<t-1&&cal(q[t-2],q[t-1])>cal(q[t-1],i))t--; 34 q[t++]=i; 35 } 36 printf("%lld",f[n]); 37 return 0; 38 }