设f[i]表示控制了1~i,第i个牧场建立了控制站,最小花费
推一下柿子
设第i个牧场的放养量是
ai
f[i]=f[j]+∑j<k<i(i−k)ak
f[i]=f[j]+i∗∑j<k<iak−∑j<k<ik∗ak
设
Si=∑ij=1aj,Vi=∑ij=1aj∗j
那么有
f[i]=f[j]+i∗(Si−1−Sj)−(Vi−1−Vj)
f[i]=i∗Si−1−Vi−1+f[j]−i∗Sj+Vj
若
j<k
,对于f[i]来说j更优时有
f[j]−i∗Sj+Vj<f[k]−i∗Sk+Vk
因为
Sj<Sk
于是
(f[j]+Vj)−(f[k]+Vk)(Sj−Sk)>i
这就是一个斜率优化了
所以维护一个斜率递增的凸包即可
读入格式都看错了竟然过了样例..
code:
#include<set>
#include<map>
#include<deque>
#include<queue>
#include<stack>
#include<cmath>
#include<ctime>
#include<bitset>
#include<string>
#include<vector>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<climits>
#include<complex>
#include<iostream>
#include<algorithm>
#define ll long long
using namespace std;
inline void read(ll &x)
{
char c;
while(!((c=getchar())>='0'&&c<='9'));
x=c-'0';
while((c=getchar())>='0'&&c<='9') (x*=10)+=c-'0';
}
const int maxn = 1000010;
struct node
{
ll x,y;
int i;
node(){}
node(const ll _x,const ll _y,const int _i){x=_x;y=_y;i=_i;}
}q[maxn]; int head,tail;
inline int multi(node p1,node p2,node p3)
{
p1.x-=p3.x; p1.y-=p3.y;
p2.x-=p3.x; p2.y-=p3.y;
return p1.x*p2.y-p1.y*p2.x;
}
inline bool cmp(node x,node y,ll k)
{return (x.y-y.y) < k*(x.x-y.x); }
//y.x-x.x==0?
int n;
ll a[maxn],c[maxn];
ll f[maxn],sck[maxn],sckk[maxn];
int main()
{
scanf("%d",&n); head=1,tail=1; q[1]=node(0,0,0);
for(int i=1;i<=n;i++) read(a[i]);
for(int i=1;i<=n;i++) read(c[i]);
for(ll i=1;i<=n;i++)
{
sck[i]=sck[i-1]+c[i]; sckk[i]=sckk[i-1]+c[i]*i;
while(head+1<=tail&&!cmp(q[head],q[head+1],i)) head++;
int j=q[head].i;
f[i]=a[i]+f[j]+i*(sck[i-1]-sck[j])-(sckk[i-1]-sckk[j]);
node tmp=node(sck[i],sckk[i]+f[i],i);
while(head+1<=tail&&multi(q[tail],tmp,q[tail-1])<=0) tail--;
q[++tail]=tmp;
}
printf("%lld\n",f[n]);
return 0;
}