码迷,mamicode.com
首页 > Windows程序 > 详细

bzoj 1911 [Apio2010]特别行动队

时间:2019-03-28 21:46:19      阅读:208      评论:0      收藏:0      [点我收藏+]

标签:pre   efi   前缀和   pac   std   span   c++   for   printf   

DP+斜率优化

dp[i]表示在前第i个士兵在特别行动队中最后一个时战斗力的最大值

sum[i]表示战斗力的前缀和

答案一定是dp[n]

dp[i]=dp[j]+a*(sum[i]-sum[j])^2+b*(sum[i]-sum[j])+c

令j优于k,则得到

2*a*sum[i]*(sum[k]-sum[j])>dp[k]+a*sum[k]^2-b*sum[k]-(dp[j]+a*sum[j]^2-b*sum[j])

令f[x]=dp[x]+a*sum[x]^2-b*sum[x]

2*a*sum[i]*(sum[k]-sum[j])>f[k]-f[j]

2*a*sum[i]>(f[k]-f[j])/(sum[k]-sum[j])

用单调队列维护即可

 

#include <bits/stdc++.h>
#define ll long long
using namespace std;
const ll MAXN=1e6+100;
ll n,a,b,c,sum[MAXN],dp[MAXN];
ll l,r,q[MAXN];
ll f(ll x)
{
    return dp[x]+a*sum[x]*sum[x]-b*sum[x];//如上
}
double xie(ll x,ll y)
{
    return ((double)f(x)-f(y))/((double)sum[x]-sum[y]);//求斜率
}
int main()
{
    scanf("%lld",&n);
    scanf("%lld%lld%lld",&a,&b,&c);
    for (ll i=1;i<=n;i++)
    {
        ll num;
        scanf("%lld",&num);
        sum[i]=sum[i-1]+num;
    }for (ll i=1;i<=n;i++)
    {
        while (l<r && xie(q[l],q[l+1])>(double)2*a*sum[i])//维护单调队列
          l++;
        dp[i]=dp[q[l]]+a*(sum[i]-sum[q[l]])*(sum[i]-sum[q[l]])+b*(sum[i]-sum[q[l]])+c;
        while (l<r && xie(q[r],i)>xie(q[r],q[r-1]))//维护单调队列
          r--;
        r++;
        q[r]=i;
    }
    printf("%lld\n",dp[n]);
}

 

bzoj 1911 [Apio2010]特别行动队

标签:pre   efi   前缀和   pac   std   span   c++   for   printf   

原文地址:https://www.cnblogs.com/huangchenyan/p/10617889.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!