bzoj3437小P的牧场

bzoj3437小P的牧场

题意:

n个牧场,在每个牧场见控制站的花费为ai,在该处建控制站能控制从此处到左边第一个控制站(或边界)之间的牧场。一个牧场被控制的花费等于它到控制它的控制站之间的牧场数目(不包括自身,但包括控制站所在牧场)乘上该牧场的放养量。求最小费用。

题解:

推公式:

f[i]=f[j]+sigma(k,j+1,i)((i-k)*b[k])+a[i]

    =f[j]+sigma(k,j+1,i)(i*b[k]-k*b[k])+a[i]

    =f[j]+sigma(k,j+1,i)(i*b[k])-sigma(k,j+1,i)(k*b[k])+a[i]

    =f[j]+i*sigma(k,j+1,i)b[k]-sigma(k,j+1,i)(k*b[k])+a[i]

sigma(k,j+1,i)b[k]和sigma(k,j+1,i)k*b[k]可用前缀和维护,故原式=f[j]+i*(sum1[i]-sum1[j])-(sum2[i]-sum2[j])+a[i],然后就可以斜率优化了:

f[j]+i*(sum1[i]-sum1[j])-(sum2[i]-sum2[j])+a[i]<f[k]+i*(sum1[i]-sum1[k])-(sum2[i]-sum2[k])+a[i]

等价于f[j]-i*sum1[j]+sum2[j]<f[k]-i*sum1[k]+sum2[k]等价于f[j]-f[k]+sum2[j]-sum2[k]<i*(sum1[j]-sum1[k]),当j<k时满足

(f[j]-f[k]+sum2[j]-sum2[k])/(sum1[j]-sum1[k])>i。

代码:

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <algorithm>
 4 #define inc(i,j,k) for(int i=j;i<=k;i++)
 5 #define maxn 1000010
 6 #define ll long long
 7 using namespace std;
 8 
 9 inline ll read(){
10     char ch=getchar(); ll f=1,x=0;
11     while(ch<'0'||ch>'9'){if(ch=='-')f=-1; ch=getchar();}
12     while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
13     return f*x;
14 }
15 ll f[maxn],sm1[maxn],sm2[maxn],a[maxn]; int n,q[maxn],l,r;
16 inline double calc(int j,int k){
17     return ((double)f[j]-f[k]+sm2[j]-sm2[k])/((double)sm1[j]-sm1[k]);
18 }
19 int main(){
20     n=read(); inc(i,1,n)a[i]=read();
21     inc(i,1,n){ll b=read(); sm1[i]=sm1[i-1]+b; sm2[i]=sm2[i-1]+b*i;} l=r=1; q[l]=0;
22     inc(i,1,n){
23         while(l<r&&calc(q[l],q[l+1])<i)l++; f[i]=f[q[l]]+i*(sm1[i]-sm1[q[l]])-sm2[i]+sm2[q[l]]+a[i];
24         while(l<r&&calc(q[r-1],q[r])>calc(q[r],i))r--; q[++r]=i;
25     }
26     printf("%lld",f[n]); return 0;
27 }

 

20160811

posted @ 2016-08-15 07:57  YuanZiming  阅读(206)  评论(0编辑  收藏  举报