小P的牧场

BZOJ

题意:\(N(N<=10^6)\)个牧场,牧场i要么花费\(a_i\)放置控制站,要么花费它到它右边第一个控制站之间的牧场数目(不包括自身,但包括控制站所在牧场)乘上该牧场的放养量\(b_i\).求最小总花费.

分析:防御准备仓库建设,这些题都差不太多.

\(f[i]\)表示在i点放置控制站的最小花费.

\(f[i]=min(f[j]+a[i]+(\sum_{k=j+1}^{i-1}b[k]*(i-k)))\)

\(sum[i]\)表示\(b[i]\)的前缀和,\(s[i]\)表示\(i*b[i]\)的前缀和,则上式可以写成

\(f[i]=f[j]+a[i]+i*(sum[i-1]-sum[j])-(s[i-1]-s[j])\)

\(k<j\)且j比k更优,即

\(f[j]+a[i]+i*(sum[i-1]-sum[j])-(s[i-1]-s[j])<f[k]+a[i]+i*(sum[i-1]-sum[k])-(s[i-1]-s[k])\)

整理上式得到,

\(\frac{f[j]+s[j]-f[k]-s[k]}{sum[j]-sum[k]}<i\)

就可以斜率优化了.

#include<bits/stdc++.h>
#define LL long long
using namespace std;
inline int read(){
   int s=0,w=1;char ch=getchar();
   while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
   while(ch>='0'&&ch<='9'){s=s*10+ch-'0';ch=getchar();}
   return s*w;
}
const int N=1000005;
int a[N],b[N],q[N];
LL s[N],sum[N],f[N];
inline double Count(int j,int k){return 1.0*(f[j]+s[j]-f[k]-s[k])/(double)(sum[j]-sum[k]);}
int main(){
    int n=read();
    for(int i=1;i<=n;i++)a[i]=read();
    for(int i=1;i<=n;i++){
		b[i]=read();
		sum[i]=sum[i-1]+b[i];
		s[i]=s[i-1]+1ll*i*b[i];
    }
    int l=1,r=1;
    for(int i=1;i<=n;i++){
		while(l<r&&Count(q[l+1],q[l])<=i)l++;
		f[i]=f[q[l]]+a[i]+i*(sum[i-1]-sum[q[l]])-(s[i-1]-s[q[l]]);
		while(l<r&&Count(q[r],q[r-1])>=Count(i,q[r]))r--;
		q[++r]=i;
    }
    printf("%lld\n",f[n]);
    return 0;
}

posted on 2019-06-13 15:57  PPXppx  阅读(249)  评论(0编辑  收藏  举报