題目描述
小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
題目分析
此題略難,參考了一下黃學長的博客
直接求最小花費是很難寫出Dp方程的,但如果轉爲從右往左求最大節約的值就很好辦了。
設f[i]表示在i~n建控制站且i建控制站,最大節約的值
不難得出方程
那麼斜率優化一下
化簡爲
令
因爲k前無負號,故求斜率要提一個負號進去
k單增,求最大值,維護上凸包
源代碼
#include<algorithm>
#include<iostream>
#include<iomanip>
#include<cstring>
#include<cstdlib>
#include<vector>
#include<cstdio>
#include<cmath>
#include<queue>
using namespace std;
typedef long long LL;
inline const LL Get_Int() {
LL num=0,bj=1;
char x=getchar();
while(x<'0'||x>'9') {
if(x=='-')bj=-1;
x=getchar();
}
while(x>='0'&&x<='9') {
num=num*10+x-'0';
x=getchar();
}
return num*bj;
}
LL n,f[1000005],Cost[1000005],sum[1000005],Q[1000005],ans=0,Cut=0;
double Slope(int j,int k) {
return (double)(f[j]-f[k])/(k-j);
}
int main() {
cin>>n;
for(int i=1; i<=n; i++)Cost[i]=Get_Int();
for(int i=1; i<=n; i++)sum[i]=sum[i-1]+Get_Int();
for(int i=1; i<n; i++)ans+=(sum[i]-sum[i-1])*(n-i);
ans+=Cost[n];
int Left=1,Right=1;
Q[1]=n;
for(int i=n-1; i>=1; i--) {
while(Left<Right&&Slope(Q[Left],Q[Left+1])>=sum[i])Left++; //維護隊首(刪除非最優決策)
int Front=Q[Left];
f[i]=f[Front]+sum[i]*(Front-i)-Cost[i];
Cut=max(Cut,f[i]);
while(Left<Right&&Slope(Q[Right-1],Q[Right])<=Slope(Q[Right],i))Right--; //維護隊尾(維護上凸包性質)
Q[++Right]=i;
}
printf("%lld\n",ans-Cut);
return 0;
}