BZOJ1911: [Apio2010]特别行动队

【传送门:BZOJ1911


简要题意:

  有n个人,每个人都有一个战力值,将这n个人分成若干个段(每个段内的人的编号都是连续的),每个段的初始战力值为每个段内的人的战力值的总和

  给出常数a,b,c,而每个段的真正战力值为ax2+bx+c(x为这个段的初始战力值),求出分成若干个段得到的所有段的最大真正战力值总和


题解:

  DP很容易想到

  设f[i]为将前i个人分成若干段的最大真正战力值,s[i]为前i个人战力值总和

  可以得到:f[i]=max(f[j]+(s[i]-s[j])*(s[i]-s[j])*a+(s[i]-s[j])*b+c)

  但这道题数据极大

  所以用斜率优化DP

  设j1<j2<i

  f[j2]+(s[i]-s[j2])*(s[i]-s[j2])*a+(s[i]-s[j2])*b+c>f[j1]+(s[i]-s[j1])*(s[i]-s[j1])*a+(s[i]-s[j1])*b+c

  化简得到:(f[j2]-f[j1]+(s[j2]*s[j2]-s[j1]*s[j1])*a-(s[j2]-s[j1])*b)/(s[j2]-s[j1])>2*a*s[i]

  然后做斜率优化就可以了

  注意要加long long

  来自蒟蒻的吐槽:这道题!!我其实应该在n久之前就应该A了,结果在斜率优化的时候把slop(list[head],list[head+1])错手打成了slop(list[head],list[head]+1),痛心疾首


参考代码:

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
using namespace std;
typedef long long LL;
LL a,b,c;
LL s[1100000];
LL f[1100000];
/*
f[i]=max(f[j]+(s[i]-s[j])*(s[i]-s[j])*a+(s[i]-s[j])*b+c)
f[i]=max(f[j]+(s[i]-s[j])*(s[i]-s[j])*a+(s[i]-s[j])*b)+c
 
j1<j2<i
f[j2]+(s[i]-s[j2])*(s[i]-s[j2])*a+(s[i]-s[j2])*b > f[j1]+(s[i]-s[j1])*(s[i]-s[j1])*a+(s[i]-s[j1])*b
f[j2]+s[i]*s[i]*a-2*a*s[i]*s[j2]+s[j2]*s[j2]*a+s[i]*b-s[j2]*b > f[j1]+s[i]*s[i]*a-2*a*s[i]*s[j1]+s[j1]*s[j1]*a+s[i]*b-s[j1]*b
f[j2]-2*a*s[i]*s[j2]+s[j2]*s[j2]*a-s[j2]*b > f[j1]-2*a*s[i]*s[j1]+s[j1]*s[j1]*a-s[j1]*b
(f[j2]-f[j1]+(s[j2]*s[j2]-s[j1]*s[j1])*a-(s[j2]-s[j1])*b)/(s[j2]-s[j1]) >2*a*s[i]
*/
LL slop(int j1,int j2)
{
    return (f[j2]-f[j1]+(s[j2]*s[j2]-s[j1]*s[j1])*a-(s[j2]-s[j1])*b)/(s[j2]-s[j1]);
}
int list[1100000];
int main()
{
    int n;
    scanf("%d",&n);
    scanf("%lld%lld%lld",&a,&b,&c);
    s[0]=0LL;
    for(int i=1;i<=n;i++)
    {
        LL x;
        scanf("%lld",&x);
        s[i]=s[i-1]+x;
    }
    int head=1,tail=1;list[1]=0;
    for(int i=1;i<=n;i++)
    {
        while(head<tail&&slop(list[head],list[head+1])>2LL*a*s[i]) head++;
        int j=list[head];
        f[i]=f[j]+(s[i]-s[j])*(s[i]-s[j])*a+(s[i]-s[j])*b+c;
        while(head<tail&&slop(list[tail-1],list[tail])<slop(list[tail],i)) tail--;
        list[++tail]=i;
    }
    printf("%lld\n",f[n]);
    return 0;
}

 

posted @ 2017-12-31 10:40  Star_Feel  阅读(108)  评论(0编辑  收藏  举报