• [APIO2010]特别行动队


    题目描述

    你有一支由 $n$ 名预备役士兵组成的部队,士兵从 $1$ 到 $n$ 编号,你要将他们拆分成若干特别行动队调入战场。出于默契的考虑,同一支特别行动队中队员的编号应该连续,即为形如 $(i, i + 1, cdots i + k)$的序列。所有的队员都应该属于且仅属于一支特别行动队。

    编号为 $i$的士兵的初始战斗力为 $x_i$,一支特别行动队的初始战斗力 $X$ 为队内士兵初始战斗力之和,即 $X = x_i + x_{i+1} + cdots + x_{i+k}$

    通过长期的观察,你总结出对于一支初始战斗力为 $X$ 的特别行动队,其修正战斗力 $X'= aX^2+bX+c$,其中 $a,~b,~c$ 是已知的系数$(a < 0)$。 作为部队统帅,现在你要为这支部队进行编队,使得所有特别行动队的修正战斗力之和最大。试求出这个最大和。

    输入格式

    输入的第一行是一个整数 $n$,代表士兵的人数。

    输入的第二行有三个用空格隔开的整数,依次代表 $a,~b,~c$,即修正战斗力的系数。

    输入的第三行有$n$个用空格隔开的整数,第 $i$ 个整数代表编号为 $i$ 的士兵的初始战斗力$x_i$

    输出格式

    输出一行一个整数,代表最大的所有特别行动队战斗力之和。

    输入输出样例

    输入 
    4 
    -1 10 -20 
    2 2 3 4 
    输出
    9

    说明/提示

    样例输入输出 1 解释

    你有 $4$ 名士兵,$x_1 = 2,~x_2 = 2,~x_3 = 3,~x_4=4$。修正战斗力公式中的参数为 $a = -1,~b = 10,~c = -20$

    此时,最佳方案是将士兵组成 $3$ 个特别行动队:第一队包含士兵 $1$ 和士兵 $2$,第二队包含士兵 $3$,第三队包含士兵 $4$。特别行动队的初始战斗力分别为 $4,~3,~4$,修正后的战斗力分别为 $-4^2 + 10 imes 4 -20 = 4$,$-3^2 - 10 imes 3 - 20 = 1$,$-4^2 + 10 imes 4 -20 = 4$。修正后的战斗力和为 $4 + 1 + 4 = 9$,没有其它方案能使修正后的战斗力和更大。

    数据范围与约定

    对于 $20\%$ 的数据,$n leq 10^3$

    对于 $50\%$的数据,$n leq 10^4$

    对于 $100\%$的数据,$1 leq n leq 10^6$$-5 leq a leq -1$$-10^7 leq b leq 10^7$$-10^7 leq c leq 10^7$$1 leq x_i leq 100$


    Solution:

    这道题应该是比较板的斜优了。
    首先把$Dp$式子写起来,设$fleft [ i ight ]$表示$1$到$i$分成若干组的最大战斗力。所以:

    $$fleft [ i ight ]= maxleft { fleft [ j ight ]+a imes left ( sumleft [ i ight ] -sumleft [ j ight ] ight )^{2}+b
    imes left ( sumleft [ i ight ] -sumleft [ j ight ] ight ) + c ight }$$

    其中$j< i$。

    把$max$去掉。因为我们要求的是$f[i]$,所以我们把已知的有关$j$的项都移到等式左边去,含$i$的未知的项都丢到右边,所以化出来就是这样:

    $$f[j]+a imes sum[j]^2-b imes sum[j]=sum[i] imes (2 imes sum[j] imes a-b-a imes sum[i])+f[i]-c$$

    所以$y=f[j]+a imes sum[j]^2-b imes sum[j]$,$k=sum[i] $,$x=2 imes sum[j] imes a-b-a imes sum[i]$,$b=f[i]-c$。

    因为我们之前求的$f[j]$是最大的,而这条直线的斜率是一定的,所以当$y$最大时,截距也最大,因为$c$是一定的,所以此时$f[i]$也最大。

    因为$sum[i]$是单调递增的,所以斜率是单调递增的,所以直接用单调队列维护即可。


    $Code:$

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 const int N=1e6+10;
     4 long long n,sum[N],x[N],l=1,r=1,q[N];
     5 long long f[N],a,b,c;
     6 long double slop(long long i,long long j){
     7     return (long double)(f[j]+a*sum[j]*sum[j]-b*sum[j]-f[i]-a*sum[i]*sum[i]+b*sum[i])/(long double)(2*a*sum[j]-2*a*sum[i]);
     8 }
     9 int main(){
    10     scanf("%lld",&n);
    11     scanf("%lld%lld%lld",&a,&b,&c);
    12     for(long long i=1;i<=n;i++){
    13         scanf("%lld",&x[i]);
    14         sum[i]=sum[i-1]+x[i];
    15     }
    16     q[1]=0;
    17     for(long long i=1;i<=n;i++){
    18         while(l<r&&slop(q[l],q[l+1])<=sum[i]) l++;
    19         f[i]=f[q[l]]+a*(sum[i]-sum[q[l]])*(sum[i]-sum[q[l]])+b*(sum[i]-sum[q[l]])+c;
    20         while(l<r&&slop(q[r-1],q[r])>=slop(q[r],i)) r--;
    21         q[++r]=i;
    22     }
    23     printf("%lld
    ",f[n]);
    24     return 0;
    25 }
  • 相关阅读:
    数独
    面向对象程序设计课第七次作业
    面向对象程序设计课第六次作业
    软件工程课总结
    第四次作业:四则运算界面
    psp记录个人项目花费时间
    作业三:代码规范,代码复查
    编写一个能生成小学四则运算题目的运算
    目前流行的源程序版本管理软件和项目管理软件有哪些?有什么优缺点
    课程进度总结
  • 原文地址:https://www.cnblogs.com/sbwll/p/14224811.html
Copyright © 2020-2023  润新知