http://www.lydsy.com/JudgeOnline/problem.php?id=3437
背景
小P是个特么喜欢玩MC的孩纸。。。
描述
小P在MC里有n个牧场,自西向东呈一字形排列(自西向东用1…n编号),于是他就烦恼了:为了控制这n个牧场,他需要在某些牧场上面建立控制站,每个牧场上只能建立一个控制站,每个控制站控制的牧场是它所在的牧场一直到它西边第一个控制站的所有牧场(它西边第一个控制站所在的牧场不被控制)(如果它西边不存在控制站,那么它控制西边所有的牧场),每个牧场被控制都需要一定的花费(毕竟在控制站到牧场间修建道路是需要资源的嘛~),而且该花费等于它到控制它的控制站之间的牧场数目(不包括自身,但包括控制站所在牧场)乘上该牧场的放养量,在第i个牧场建立控制站的花费是ai,每个牧场i的放养量是bi,理所当然,小P需要总花费最小,但是小P的智商有点不够用了,所以这个最小总花费就由你来算出啦。
第一行一个整数 n 表示牧场数目
第二行包括n个整数,第i个整数表示ai
第三行包括n个整数,第i个整数表示bi
只有一行,包括一个整数,表示最小花费
4
2424
3142
9
样例解释
选取牧场1,3,4建立控制站,最小费用为2+(2+1*1)+4=9。
数据范围与约定
对于100%的数据,1<=n<=1000000,0
斜率优化dp
倒着做
dp[i]表示第i个位置放置控制站最多能够省下多少钱
显然dp[i] = max(dp[i],dp[j]+sum[i]*(j-i)-a[i]);
这个方程也显然是可以斜率优化dp的
假设j>k,dp[j]>dp[k]
则可以推出:dp[j]+sumi-a[i]>dp[k]+sumi-a[i]
dp[j]-dp[k]/k-j > sum[i]
然后斜率优化跑一波就变成O(n)了
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e6+8;
long long a[maxn],b[maxn],sum[maxn],dp[maxn],tot,ans;
int n,q[maxn],l,r;
double slope(int i,int j)
{
double up = dp[i]-dp[j];
double down = j - i;
return up/down;
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%lld",&a[i]);
for(int i=1;i<=n;i++)
{
scanf("%lld",&b[i]);
sum[i]=sum[i-1]+b[i];
tot+=(b[i]*(n-i));
}
q[r]=n;
tot+=a[n];
for(int i=n-1;i;i--)
{
while(l<r&&slope(q[l+1],q[l])>sum[i])l++;
int now = q[l];
dp[i]=dp[now]+sum[i]*(now-i)-a[i];
ans = max(ans,dp[i]);
while(l<r&&slope(i,q[r])>slope(q[r],q[r-1]))r--;
q[++r]=i;
}
printf("%lld\n",tot-ans);
}