Description
背景
小P是个特么喜欢玩MC的孩纸。。。
描述
小P在MC里有n个牧场,自西向东呈一字形排列(自西向东用1…n编号),于是他就烦恼了:为了控制这n个牧场,他需要在某些牧场上面建立控制站,每个牧场上只能建立一个控制站,每个控制站控制的牧场是它所在的牧场一直到它西边第一个控制站的所有牧场(它西边第一个控制站所在的牧场不被控制)(如果它西边不存在控制站,那么它控制西边所有的牧场),每个牧场被控制都需要一定的花费(毕竟在控制站到牧场间修建道路是需要资源的嘛~),而且该花费等于它到控制它的控制站之间的牧场数目(不包括自身,但包括控制站所在牧场)乘上该牧场的放养量,在第i个牧场建立控制站的花费是ai,每个牧场i的放养量是bi,理所当然,小P需要总花费最小,但是小P的智商有点不够用了,所以这个最小总花费就由你来算出啦。
Input
第一行一个整数 n 表示牧场数目
第二行包括n个整数,第i个整数表示ai
第三行包括n个整数,第i个整数表示bi
Output
只有一行,包括一个整数,表示最小花费
Sample Input
2424
3142
Sample Output
9
样例解释
选取牧场1,3,4建立控制站,最小费用为2+(2+1*1)+4=9。
数据范围与约定
对于100%的数据,1<=n<=1000000,0<ai,bi<=10000
斜率优化的dp
有点麻烦
f[i]表示1~i中在i放控制站的最小代价
那么f[i]=min(f[j]+a[i]+Σb[k]*(i-k)|j<k<=i)
然后算Σ的式子的时候首先b[i]可以用前缀和优化一下
首先原式
=s[i-1]-s[j]
+s[i-2]-s[j]
+s[i-3]-s[j]
……
+s[j+1]-s[j]
所以再搞出s[]的前缀和t[]
那么最后化简完f[i]=min(f[j]+a[i]+t[i-1]-t[j]-s[j]*(i-j-1));
然后考虑转移i的状态的时候,有j,k两个决策
当f[j]+a[i]+t[i-1]-t[j]-s[j]*(i-j-1)<f[k]+a[i]+t[i-1]-t[k]-s[k]*(i-k-1)时j比k优
即f[j]-s[j]-(f[k]-s[k])+s[j]*(j+1)-s[k]*(k+1)<i*(s[j]-s[k])
于是可以用斜率优化了
#include<cstdio> #include<iostream> #include<cstring> #include<cstdlib> #include<algorithm> #include<cmath> #include<queue> #include<deque> #include<set> #include<map> #include<ctime> #define LL long long #define inf 10000000000000000ll #define pa pair<int,int> #define pi 3.1415926535897932384626433832795028841971 #define N 1000010 using namespace std; inline LL read() { LL x=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} return x*f; } LL s[N],t[N],f[N]; int a[N],b[N]; int q[N],head,tail=1; LL cala(int x,int y) { return f[x]-f[y]-(t[x]-t[y])+(s[x]*(x+1)-s[y]*(y+1)); } LL calb(int x,int y) { return s[x]-s[y]; } int n; int main() //f[i]=min(f[j]+a[i]+t[i-1]-t[j]-s[j]*(i-j-1)); { freopen("pasture.in","r",stdin); freopen("pasture.out","w",stdout); n=read(); for (int i=1;i<=n;i++)f[i]=inf; for (int i=1;i<=n;i++)a[i]=read(); for (int i=1;i<=n;i++)b[i]=read(); for (int i=1;i<=n;i++) { s[i]=s[i-1]+b[i]; t[i]=t[i-1]+s[i]; } for (int i=1;i<=n;i++) { while (tail-head>1 && cala(q[head+1],q[head])<=i*calb(q[head+1],q[head]))head++; int from=q[head]; f[i]=f[from]+a[i]+t[i-1]-t[from]-s[from]*(i-from-1); q[tail++]=i; for (int k=tail-2;k>head;k--) { int x=q[k+1],y=q[k],z=q[k-1]; if (cala(y,z)*calb(x,y)>=cala(x,y)*calb(y,z))q[k]=q[--tail]; else break; } } printf("%lld\n",f[n]); }