题目描述

给你一个数列,让你将这个数列分成若干段,使其每一段的和的\(a \times sum^2 + b \times sum + c\)的总和最大。

分析

算是一道斜率优化的入门题。
首先肯定是考虑\(O(n^2)\)的暴力DP。
定义状态\(f[i]\)表示最后一段的结尾是\(i\)的最大答案。
那么枚举j,得到转移方程为\(f[i]=max(f[i],f[j]+a\times (sum[i]-sum[j])^2+b\times(sum[i]-sum[j])+c\)
注意这里的转移方程不是\(sum[i]-sum[j-1]\)而是\(sum[i]-sum[j]\),因为j是属于前一段的,所以不能算j-1这一个格子。
40分蜜汁错误和全部剩下全部T飞。

#include <bits/stdc++.h>
#define ll long long
#define ms(a, b) memset(a, b, sizeof(a))
#define inf 0x3f3f3f3f
#define N 1000005
using namespace std;
template <typename T>
inline void read(T &x) {
    x = 0; T fl = 1;
    char ch = 0;
    while (ch < '0' || ch > '9') {
        if (ch == '-') fl = -1;
        ch = getchar();
    }
    while (ch >= '0' && ch <= '9') {
        x = (x << 1) + (x << 3) + (ch ^ 48);
        ch = getchar();
    }
    x *= fl;
}
ll sqr(ll x) {
    return x * x;
}
int n;
ll a, b, c;
ll x[N], sum[N], f[N];
int main() {
    read(n);
    read(a); read(b); read(c);
    for (int i = 1; i <= n; i ++)  {
        read(x[i]);
        sum[i] = sum[i - 1] + x[i];
    }
    for (int i = 1; i <= n; i ++)
        for (int j = 0; j < i; j ++)
            f[i] = max(f[i], f[j] + sqr(sum[i] - sum[j]) * a + (sum[i] - sum[j]) * b + c);
    printf("%lld\n", f[n]);
    return 0;
}

很显然这不是正解,那么我们就考虑优化DP。
考虑斜率优化。按照斜率优化的标准套路。
假设\(0<=k<j<i\)时,j的状态比k要优。。
那么很明显就得到了以下的式子,再将其化简:
\[f_j+a\times(sum_i-sum_j)^2+b\times(sum_i-sum_j)+c>=f_k+a\times a\times(sum_i-sum_j)^2+b\times(sum[i]-sum[j])+c\]
以下的所有操作都是初中内容。(可能会跳步,但是看得懂)
\[f_j-2asum_isum_j+asum_j^2-bsum_j>=f_k-2asum_isum_k+asum_k^2-bsum_k\]
\[\frac{(f_j+asum_j^2-bsum_j)-(f_k+asum_k^2-bsum_k)}{sum_j-sum_k}>=2sum_i\]
可以发现:左边单调递增,右边单调递减。那么维护斜率上凸包。

#include <bits/stdc++.h>
#define ll long long
#define ms(a, b) memset(a, b, sizeof(a))
#define inf 0x3f3f3f3f
#define N 1000005
#define db double
using namespace std;
template <typename T>
inline void read(T &x) {
    x = 0; T fl = 1;
    char ch = 0;
    while (ch < '0' || ch > '9') {
        if (ch == '-') fl = -1;
        ch = getchar();
    }
    while (ch >= '0' && ch <= '9') {
        x = (x << 1) + (x << 3) + (ch ^ 48);
        ch = getchar();
    }
    x *= fl;
}
ll sqr(ll x) {
    return x * x;
}
int n;
ll a, b, c;
ll x[N], sum[N], f[N];
int q[N];
ll get_x(int i) {
    return sum[i];
}
ll get_y(int i) {
    return f[i] + a * sqr(sum[i]) - b * sum[i];
}
db get_slope(int i, int j) {
    return (1.0 * (get_y(j) - get_y(i))) / (1.0 * (get_x(j) - get_x(i)));
}
int main() {
    read(n);
    read(a); read(b); read(c);
    for (int i = 1; i <= n; i ++)  {
        read(x[i]);
        sum[i] = sum[i - 1] + x[i];
    }
    int h = 0, t = 0;
    for (int i = 1; i <= n; i ++) {
        while (h < t && get_slope(q[h] , q[h + 1]) >= 2.0 * a * sum[i]) h ++;
        int j = q[h];
        f[i] = f[j] + a * sqr(sum[i] - sum[j]) + b * (sum[i] - sum[j]) + c;
        while (h < t && get_slope(q[t - 1], q[t]) <= get_slope(q[t], i)) t --;
        q[++ t] = i;
    }
    printf("%lld\n", f[n]);
    return 0;
}

[luogu3628][bzoj1911][APIO2010]特别行动队【动态规划+斜率优化DP】的更多相关文章

  1. BZOJ1911 [Apio2010]特别行动队 - 动态规划 - 斜率优化

    欢迎访问~原文出处——博客园-zhouzhendong 去博客园看该题解 题目传送门 UPD(2018-04-01):用Latex重打了公式…… 题意概括 把一个整数序列划分成任意连续的段,使得划分出 ...

  2. 2018.09.07 bzoj1911: [Apio2010]特别行动队(斜率优化dp)

    传送门 斜率优化dp经典题. 题目中说的很清楚,设f[i]表示前i个数分配出的最大值. 那么有: f[i]=max(f[j]+A∗(sum[i]−sum[j])2+B∗(sum[i]−sum[j])+ ...

  3. [bzoj1911][Apio2010特别行动队] (动态规划+斜率优化)

    Description Input Output Sample Input - - Sample Output HINT Solution 斜率优化动态规划 首先易得出这样的一个朴素状态转移方程 f[ ...

  4. BZOJ1911 [Apio2010]特别行动队 【斜率优化】

    1911: [Apio2010]特别行动队 Time Limit: 4 Sec  Memory Limit: 64 MB Submit: 5005  Solved: 2455 [Submit][Sta ...

  5. bzoj 1911 [Apio2010]特别行动队(斜率优化+DP)

    1911: [Apio2010]特别行动队 Time Limit: 4 Sec  Memory Limit: 64 MBSubmit: 3191  Solved: 1450[Submit][Statu ...

  6. P3628 [APIO2010]特别行动队(斜率优化dp)

    P3628 [APIO2010]特别行动队 设$s[i]$为战斗力前缀和 显然我们可以列出方程 $f[i]=f[j]+a*(s[i]-s[j])^{2}+b*(s[i]-s[j])+c$ $f[i]= ...

  7. 【BZOJ】1911: [Apio2010]特别行动队(斜率优化dp)

    题目 传送门:QWQ 分析 用$ dp[i] $ 表示前 i 个人组成的战斗力之和 然后显然$ dp[i]=Max (  dp[j]+a*(sum[i]-sum[j])^2+b*(sum[i]-sum ...

  8. _bzoj1911 [Apio2010]特别行动队【斜率优化dp】

    传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=1911 裸的斜率优化dp. #include <cstdio> const int ...

  9. bzoj 1911: [Apio2010]特别行动队【斜率优化dp】

    仔细想想好像没学过斜率优化.. 很容易推出状态转移方程\( f[i]=max{f[j]+a(s[i]-s[j])^2+b(s[i]-s[j])+c} \) 然后考虑j的选取,如果选j优于选k,那么: ...

  10. 【BZOJ 1191】 [Apio2010]特别行动队 (斜率优化)

    dsy1911: [Apio2010]特别行动队 [题目描述] 有n个数,分成连续的若干段,每段的分数为a*x^2+b*x+c(a,b,c是给出的常数),其中x为该段的各个数的和.求如何分才能使得各个 ...

随机推荐

  1. 软工+C(8): 提问与回复

    // 上一篇:野生程序员 // 下一篇:助教指南 在线上博客教学里引入了第三方助教,助教在每次作业期间尽力完成"消灭零点评"的目标.然而紧接而来的问题是:学生对博客作业点评的回复率 ...

  2. Ubuntu18.04更新源

    一.备份/etc/apt/sources.list文件 cd /etc/apt sudo cp sources.list sources.list.old 二.选择国内常用的源 #阿里源 deb ht ...

  3. php开发之常用验证方法

    1.邮箱验证 function isEmail($email) { if (!$email) { return false; } return preg_match('/^[_\.0-9a-z-]+@ ...

  4. React Native之FlatList的介绍与使用实例

    React Native之FlatList的介绍与使用实例 功能简介 FlatList高性能的简单列表组件,支持下面这些常用的功能: 完全跨平台. 支持水平布局模式. 行组件显示或隐藏时可配置回调事件 ...

  5. Linux 查找文件命令 find whereis locate

    Linux 有三个查找文件的命令:find, whereis, locate 其中find 不常用,whereis与locate经常使用,因为find命令速度较慢,因为whereis与locate是利 ...

  6. select into赋值方式

    declare v_price ,);--单价 v_usenum number;--水费字数 v_usenum2 number;--使用吨数 begin v_price:=2.45;--每吨单价 -- ...

  7. Java8 Lambda和Stream的用法

    package com.zhangxueliang.demo; import java.util.ArrayList; import java.util.List; import java.util. ...

  8. JavaMail入门第一篇 邮件简介及API概述

    现如今,电子邮件在我们的生活当中扮演着越来越重要的角色,我们每个人几乎都会与其打交道(至少时不时我们都会接收到莫名其妙的垃圾邮件),在工作中,使用邮件进行交流沟通,可以使我们的工作有迹可循,也显的较为 ...

  9. C++多态(静多态和动多态)

    如今的C++已经是个多重泛型编程语言(multiparadigm programming lauguage),一个同时支持过程形式(procedural).面向对象形式(object-oriented ...

  10. php redis常用方法代码例子

    1,connect 描述:实例连接到一个Redis.参数:host: string,port: int返回值:BOOL 成功返回:TRUE;失败返回:FALSE 示例: <?php $redis ...