T2 牧场 by greens 1s 128M (pasture.cpp)
背景
小 P 是个特么喜欢玩 MC 的孩纸。。。
描述
小 P 在 MC 里有 n 个牧场,自西向东呈一字形排列(自西向东用 1…n 编号),于是他就烦恼了:为了控制这 n 个牧场,他需要在某些牧场上面建立控制站,每个牧场上只能建立一个控制站,每个控制站控制的牧场是它所在的牧场一直到它西边第一个控制站的所有牧场(它西边第一个控制站所在的牧场不被控制)(如果它西边不存在控制站,那么它控制西边所有的牧场),每个牧场被控制都需要一定的花费(毕竟在控制站到牧场间修建道路是需要资源的嘛~),而且该花费等于它到控制它的控制站之间的牧场数目(不包括自身,但包括控制站所在牧场)乘上该牧场的放养量,在第 i 个牧场建立控制站的花费是 ai,每个牧场 i 的放养量是 bi,理所当然,小 P 需要总花费最小,但是小 P的智商有点不够用了,所以这个最小总花费就由你来算出啦。
输入格式
第一行一个整数 n 表示牧场数目
第二行包括 n 个整数,第 i 个整数表示 ai
第三行包括 n 个整数,第 i 个整数表示 bi
输出格式
只有一行,包括一个整数,表示最小花费
样例输入
4
2 4 2 4
3 1 4 2
样例输出
9
样例解释
选取牧场 1,3,4 建立控制站,最小费用为 2+( 2 + 1 * 1 ) + 4 = 9。
数据范围与约定
对于 10%的数据,1 <= n <= 10
对于 30%的数据,1 <= n <= 1000
对于 100%的数据,1 <= n <= 1000000 , 0 < ai,bi <= 10000
思路:
转移方程:f[i]=f[j]+a[i]+(ll)i*(sum[i-1]-sum[j])-(s[i-1]-s[j])
如果不理解就自己手玩一下,造个数据代入测试也可
之后发现如果n^2复杂度做不了100%的数据,由于方程式满足斜率优化方程式的一般规律,考虑斜率优化
代码:
#include<bits/stdc++.h>
#define ll long long
#define maxn 1000010
using namespace std;
ll f[maxn],sum[maxn],s[maxn];
inline ll read()//快读
{
char c=getchar();
ll x=0,f=1;
while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}//不需要判负删掉来简化
while(isdigit(c))x=(x<<3)+(x<<1)+(c^48),c=getchar();
return x*f;
}
ll q[maxn];
ll a[maxn],b[maxn];
ll getup(ll j,ll k)
{
return f[j]+s[j]-(f[k]+s[k]);
}
ll getdone(ll j,ll k)
{
return sum[j]-sum[k];
}
ll getdp(ll i,ll j)
{
// cout<<i<<" sgsr "<<j<<'
';
return f[i]=f[j]+a[i]+(ll)i*(sum[i-1]-sum[j])-(s[i-1]-s[j]);
// f[i]=f[q[head]]+a[i]+i*(sum[i-1]-sum[q[head]])-(s[i-1]-s[q[head]]);
}
ll n;
int main()
{
freopen("pasture.in","r",stdin);
freopen("pasture.out","w",stdout);
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];
}
ll head=1,tail=1;
q[1]=0;
for(int i=1;i<=n;i++)//对于每一个i枚举断点
{
while(head<tail&&getup(q[head+1],q[head])
<=(ll)i*getdone(q[head+1],q[head]))
head++/*,cout<<1<<" "*/;
// cout<<'
';
f[i]=getdp(i,q[head]);
// ll j=q[head];
// f[i]=f[j]+a[i]+i*(sum[i-1]-sum[j])-(s[i-1]-s[j]);
while(head<tail&&(ll)getup(i,q[tail])*getdone(q[tail],q[tail-1])
<=(ll)getup(q[tail],q[tail-1])*getdone(i,q[tail]))
//如果i与tail的斜率比tail-1与tail的斜率小,说明tail不合法,直接删除
tail--/*,cout<<2<<" "*/;
// cout<<'
';
q[++tail]=i;
// cout<<head<<" "<<tail<<'
';
}
/*int l=1,r=1;
for(int i=1;i<=n;i++){
while(l<r&&getup(q[l+1],q[l])<=i*getdone(q[l+1],q[l]))l++;
f[i]=f[q[l]]+a[i]+i*(sum[i-1]-sum[q[l]])-(s[i-1]-s[q[l]]);
while(l<r&&getup(q[r],q[r-1])*getdone(i,q[r])>=getup(i,q[r])*getdone(q[r],q[r-1]))r--;
q[++r]=i;
cout<<l<<" "<<r<<'
';
}*/
cout<<f[n]<<'
';
}