bzoj1911 [Apio2010]特别行动队(斜率优化)

f[i]表示前i个人能获得的最大战力。
f[i]=max{f[j]+w(j+1,i)|1<=j< i}.w(j+1,i)表示j+1…i组成一队获得的战斗力,把sum[i]-sum[j]代入公式即可。如果k1< k2且k1优于k2:
f[k1]-f[k2]+a*sum[k1]^2-a*sum[k2]^2+b*(sum[k2]-sum[k1])>2*a*(sum[k1]-sum[k2])*sum[i]。还是维护一个下凸曲线,保证队列中的斜率单增。

#include <cstdio>
#include <cstring>
#define ll long long
int const N=1000010;
int n,a,b,c,q[N],h=0,t=0;
ll f[N],sum[N];
inline int read(){
    int 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;
}
inline double slope(int k1,int k2){//注意加括号啊。。 
    return (f[k1]-f[k2]+a*(sum[k1]*sum[k1]-sum[k2]*sum[k2])+b*(sum[k2]-sum[k1]))*1.0/(2.0*a*(sum[k1]-sum[k2]));
}
int main(){
//  freopen("a.in","r",stdin);
    n=read();a=read();b=read();c=read();
    for(int i=1;i<=n;++i){int x=read();sum[i]=sum[i-1]+x;}
    for(int i=1;i<=n;++i){
        while(h<t&&slope(q[h],q[h+1])<(double)sum[i]) h++;
        f[i]=f[q[h]]+a*((sum[i]-sum[q[h]])*(sum[i]-sum[q[h]]))+b*(sum[i]-sum[q[h]])+c;
        while(h<t&&slope(q[t],i)<slope(q[t-1],q[t])) t--;
        q[++t]=i;
    }
    printf("%lld",f[n]);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值