这道题,需要选两个锯木厂,标定了选的份数,以前做的题都是可以分成任意的分数
实际上,这道题n^2枚举锯木厂的位置,O( 1 ) 计算,找出最大值。
算是斜率优化,感觉不是特别好说是斜率优化dp,因为这道题,当确定了第二个锯木厂,第一个锯木厂的选择是有决策单调性,其实斜率优化就是用了处理决策单调性的问题决策选取的,这道题推式子可以推出来斜率式,能推出斜率的式子,就可以来用单调队列维护决策处理单调性了
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
using namespace std;
typedef long long ll;
ll sum[200505],dis[200505],f[200505],ans=20000000005,s[200505];
int n,q[200505],head,tail;
ll getup(int j,int k)
{
return dis[j+1]*sum[j]-dis[k+1]*sum[k];
}
ll getdown(int j,int k)
{
return dis[j+1]-dis[k+1];
}
ll getdp(int i,int j)
{
return -dis[j+1]*(sum[i]-sum[j]) +
s[n]-dis[i+1]*(sum[n]-sum[i]);
}
int main()
{
freopen("two.in","r",stdin);
freopen("two.out","w",stdout);
scanf("%d",&n);
for (int i=n;i>=1;i--) scanf("%lld%lld",&sum[i],&dis[i]);
for (int i=1;i<=n;i++) dis[i]+=dis[i-1],sum[i]+=sum[i-1];
for (int i=1;i<=n;i++) s[i]=s[i-1]+(sum[i]-sum[i-1])*dis[i];
head=tail=1;
q[head]=0;
f[0]=0;//?
for (int i=1;i<n;i++)
{
while (head<tail &&
getup(q[head+1],q[head])<sum[i]*getdown(q[head+1],q[head])
) head++;
f[i]=getdp(i,q[head]);
while (head<tail &&
getup(i,q[tail])*getdown(q[tail],q[tail-1])<
getup(q[tail],q[tail-1])*getdown(i,q[tail])
) tail--;
q[++tail]=i;
ans=min(ans,f[i]);
}
printf("%lld",ans);
return 0;
}