【動態規劃24】bzoj3437小P的牧場(dp+斜率優化)

題目描述

小P在MC裏有n個牧場,自西向東呈一字形排列(自西向東用1…n編號),於是他就煩惱了:爲了控制這n個牧場,他需要在某些牧場上面建立控制站,每個牧場上只能建立一個控制站,每個控制站控制的牧場是它所在的牧場一直到它西邊第一個控制站的所有牧場(它西邊第一個控制站所在的牧場不被控制)(如果它西邊不存在控制站,那麼它控制西邊所有的牧場),每個牧場被控制都需要一定的花費(畢竟在控制站到牧場間修建道路是需要資源的嘛~),而且該花費等於它到控制它的控制站之間的牧場數目(不包括自身,但包括控制站所在牧場)乘上該牧場的放養量,在第i個牧場建立控制站的花費是ai,每個牧場i的放養量是bi,理所當然,小P需要總花費最小,但是小P的智商有點不夠用了,所以這個最小總花費就由你來算出啦。

輸入輸出格式

第一行一個整數 n 表示牧場數目
第二行包括n個整數,第i個整數表示ai
第三行包括n個整數,第i個整數表示bi
只有一行,包括一個整數,表示最小花費

f[i]表示在i建站的最小花費。
f[i]=min(f[j]+ik=j+1b[k](ik)+a[i])(j<i)
考慮前綴優化
右式可變爲f[j]+ik=j+1(b[k]ib[k]k)
那麼預處理b[j]與b[j]*j前綴
那麼該式可變爲(b[]爲原b[]的前綴和,pre[j]爲b[j]*j的前綴和)
f[j]+(b[i]b[j])i(pre[i]pre[j])+a[i]
j<k 且且k優於j
f[j]+(b[i]b[j])i(pre[i]pre[j])+a[i]>f[k]+(b[i]b[k])i(pre[i]pre[k])+a[i]
f[j]b[j]i+pre[j]>f[k]b[k]i+pre[k]
(b[k]b[j])i>f[k]f[j]+pre[k]pre[j]
i>f[k]f[j]+pre[k]pre[j]b[k]b[j]

#include<bits/stdc++.h>
#define ll long long
#define pa pair<int,int>
#define fer(i,j,n) for(int i=j;i<=n;i++)
#define far(i,j,n) for(int i=j;i>=n;i--)
const int INF=1e9;
const int maxn=1000010;
using namespace std;
/*----------------------------------------------------*/
inline ll read()
{
    char ls;int x=0,sng=1;
    for(;ls<'0'||ls>'9';ls=getchar())if(ls=='-')sng=-1;
    for(;ls>='0'&&ls<='9';ls=getchar())x=x*10+ls-'0';
    return x*sng;
}
/*----------------------------------------------------*/
ll a[maxn],b[maxn],pre[maxn];
ll f[maxn],q[maxn];
int n;
ll calcK(int j,int k)
{
    return (f[k]-f[j]+pre[k]-pre[j])/(b[k]-b[j]);
}
int main()
{
    n=read();
    memset(b,0,sizeof(b));
    memset(pre,0,sizeof(pre));
    fer(i,1,n)
        a[i]=read();
    fer(i,1,n)
    {
        b[i]=read();
        pre[i]=b[i]*i+pre[i-1];
        b[i]+=b[i-1];
    }
    int h=0,t=0;
    fer(i,1,n)
    {
        while(h<t&&calcK(q[h],q[h+1])<i)h++;
        f[i]=f[q[h]]+(b[i]-b[q[h]])*i-(pre[i]-pre[q[h]])+a[i];
        while(h<t&&calcK(q[t],q[t-1])>calcK(i,q[t]))t--;
        q[++t]=i;
    }
    cout<<f[n];
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章