zoukankan      html  css  js  c++  java
  • 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
    ",f[n]);
        return 0;
    }

     

  • 相关阅读:
    Study Plan The TwentySecond Day
    Study Plan The Nineteenth Day
    Study Plan The TwentySeventh Day
    Study Plan The Twentieth Day
    Study Plan The TwentyFirst Day
    python实现进程的三种方式及其区别
    yum makecache
    JSONPath 表达式的使用
    oracle执行cmd的实现方法
    php daodb插入、更新与删除数据
  • 原文地址:https://www.cnblogs.com/Never-mind/p/8157186.html
Copyright © 2011-2022 走看看