[BZOJ3437] 小 P 的牧场

描述 Description

小 P 在 MC 里有 n 个牧场,自西向东呈一字形排列(自西向东用 1…n 编号),于是他就烦恼了:为了控制这 n 个牧场,他需要在某些牧场上面建立控制站,每个牧场上只能建立一个控制站,每个控制站控制的牧场是它所在的牧场一直到它西边第一个控制站的所有牧场(它西边第一个控制站所在的牧场不被控制)(如果它西边不存在控制站,那么它控制西边所有的牧场),每个牧场被控制都需要一定的花费(毕竟在控制站到牧场间修建道路是需要资源的嘛~),而且该花费等于它到控制它的控制站之间的牧场数目(不包括自身,但包括控制站所在牧场)乘上该牧场的放养量,在第 i 个牧场建立控制站的花费是 ai,每个牧场 i 的放养量是 bi,理所当然,小 P 需要总花费最小,但是小 P 的智商有点不够用了,所以这个最小总花费就由你来算出啦。

输入格式 InputFormat

第一行一个整数 n 表示牧场数目

第二行包括 n 个整数,第 i 个整数表示 ai

第三行包括 n 个整数,第 i 个整数表示 bi

输出格式 OutputFormat

只有一行,包括一个整数,表示最小花费

样例输入 SampleInput

4
2 4 2 4
3 1 4 2

样例输出 SampleOutput

9


BZOJ 3437


斜率优化 DP。

原始方程: \[ f[i]=f[j]+\sum_{k=j+1}^{i}((i-k)*b[k])+a[i] \]

展开后得到 \[ f[i]=f[j]+i*\sum_{k=j+1}^{i}b[k]-\sum_{k=j+1}^{i}k*b[k] \]

用 $ sum1[i] $ 表示 $ _{k=1}^{i}b[k] \(,\) sum2[i] $ 表示 $ _{k=1}^{i}(k*b[k]) $

则方程化为 \[ f[i]=f[j]+i*(sum1[i]-sum1[j])-sum2[i]+sum2[j]+a[i] \]

设 $ k #include #include #include #include using namespace std; #define ll long long const int maxn=1000005; ll i,j,t,n,m,l,r,k,z,y,x; ll a[maxn],b[maxn]; ll sum1[maxn],sum2[maxn],f[maxn],q[maxn]; ll head,tail; inline ll fracup(ll x,ll y) { return (ll)f[x]+sum2[x]-f[y]-sum2[y]; } inline ll fracdown(ll x,ll y) { return (ll)sum1[x]-sum1[y]; } int main() { scanf(“%lld”,&n); sum1[0]=sum2[0]=0; for (i=1;i<=n;i++) scanf(“%lld”,&a[i]); for (i=1;i<=n;i++) scanf(“%lld”,&b[i]),sum1[i]=sum1[i-1]+b[i],sum2[i]=sum2[i-1]+(ll)b[i]i; head=tail=0;q[head]=0; for (i=1;i<=n;i++) { while (tail>head && fracup(q[head+1],q[head])head && fracup(q[tail],q[tail-1])fracdown(i,q[tail])>fracup(i,q[tail])*fracdown(q[tail],q[tail-1])) tail–; q[++tail]=i; } printf(“%lld”,f[n]); return 0; } ```