特别行动队
【问题描述】
你有一支由 n 名预备役士兵组成的部队,士兵从 1 到 n 编号,要将他们拆分成若干特别行动队调入战场。出于默契的考虑,同一支特别行动队中队员的编号应该连续,即为形如(i, i + 1, …, i + k)的序列。
编号为 i 的士兵的初始战斗力为 xi ,一支特别行动队的初始战斗力 x 为队内士兵初始战斗力之和,即 x = xi + xi+1 + … + xi+k。
通过长期的观察,你总结出一支特别行动队的初始战斗力 x 将按如下经验公式修正为 x':x' = ax2 + bx + c,其中 a, b, c 是已知的系数(a < 0)。
作为部队统帅,现在你要为这支部队进行编队,使得所有特别行动队修正后战斗力之和最大。试求出这个最大和。
例如,你有 4 名士兵,x1 = 2, x2 = 2, x3 = 3, x4 = 4。经验公式中的参数为 a = –1,b = 10, c = –20。此时,最佳方案是将士兵组成 3 个特别行动队:第一队包含士兵
1 和士兵 2,第二队包含士兵 3,第三队包含士兵 4。特别行动队的初始战斗力分别为 4, 3, 4,修正后的战斗力分别为 4, 1, 4。修正后的战斗力和为 9,没有其它
方案能使修正后的战斗力和更大。
【输入格式】
输入由三行组成。第一行包含一个整数 n,表示士兵的总数。第二行包含三个整数 a, b, c,经验公式中各项的系数。第三行包含 n 个用空格分隔的整数 x1,x2, …, xn,分别表示编号为 1, 2, …, n 的士兵的初始战斗力。
【输出格式】
输出一个整数,表示所有特别行动队修正后战斗力之和的最大值。
【样例输入】
4
-1 10 -20
2 2 3 4
【样例输出】
9
【数据范围】
20%的数据中,n ≤ 1000;
50%的数据中,n ≤ 10,000;
100%的数据中,1 ≤ n ≤ 1,000,000,–5 ≤ a ≤ –1,|b| ≤ 10,000,000,|c| ≤10,000,000,1 ≤ xi ≤ 100。

之所以用这道题练手是因为印象中其方程特别裸:f[i] = max{f[j] + a * sum(j + 1, i) ^ 2 + b * sum(j + 1, i) + c}。

如何用所谓的斜率优化来写这道题呢?这不像二分栈一样,一看到就可以直接写,反正不会错,而是需要证明并求出斜率才可以。

如何求斜率呢?我套用一般资料上所说的方法:设决策 j > k 且 g[k] > g[j] (g 为转移的代价),则可以展开代价得到一个类似于斜率的不等式:

(yk - yj) / (xk - xj) < h[i] (y 和 x 分别为随决策变化的表达式,而h[i] 为与 k, j 无关而仅与转出有关的常数,总之就是移项然后除一下)。

如此只要不等式成立且 h[i] 随 i 单调递增,则 k 决策将永远优于 j 决策(因为这里所用的是小于号,如果当前小于那么就会一直小于)。

如何利用这个性质呢?可以用单调队列维护决策和斜率单调,并且每次剔除无用决策。同于一般的单调队列优化,每个元素出队入队最多一次,所以时间复杂度为 O(n) 。

至于编程复杂度,完虐二分栈。。。。而且常数和时间复杂度也都优很多。。。试想 100w 或 200w 的数据而时限 1s,二分栈可以跑到一两秒,而斜率优化无压力。。。

Code :

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>#define swap(a, b, t) ({t _ = (a); (a) = (b); (b) = _;})
#define max(a, b) ({int _ = (a), __ = (b); _ > __ ? _ : __;})
#define min(a, b) ({int _ = (a), __ = (b); _ < __ ? _ : __;})#define maxn 1000005#define sqr(a) ({double _ = (a); _ * _;})int n, h, t;
int q[maxn];
double a, b, c;
double x[maxn], s[maxn], f[maxn];double slope(int i, int j)
{return (f[j] - f[i] + a * (sqr(s[j]) - sqr(s[i])) + b * (s[i] - s[j])) / (s[j] - s[i]);
}int main()
{freopen("commando.in", "r", stdin);freopen("commando.out", "w", stdout);scanf("%d%lf%lf%lf", & n, & a, & b, & c);for (int i = 1; i <= n; ++ i)scanf("%lf", & x[i]), s[i] = s[i - 1] + x[i];q[++ t] = 0;for (int i = 1; i <= n; ++ i){while (h + 1 < t && slope(q[h + 2], q[h + 1]) > 2 * a * s[i]) ++ h;f[i] = f[q[h + 1]] + a * sqr(s[i] - s[q[h + 1]]) + b * (s[i] - s[q[h + 1]]) + c;while (t - 1 > h && slope(q[t - 1], q[t]) < slope(q[t], i)) -- t; q[++ t] = i;}printf("%.0lf\n", f[n]);return 0;
}

再是二分栈的代码,瞬间长了一倍(包括头文件等),而且抛开读入慢得多:

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <climits>
#include <iostream>
#include <algorithm>typedef double TYPE;
typedef long long int64;
typedef unsigned int uint;
typedef unsigned long long uint64;#define swap(a, b, t) ({t _ = (a); (a) = (b); (b) = _;})
#define MAX(a, b, t) ({t _ = (a), __ = (b); _ > __ ? _ : __;})
#define MIN(a, b, t) ({t _ = (a), __ = (b); _ < __ ? _ : __;})
#define max(a, b) ({TYPE _ = (a), __ = (b); _ > __ ? _ : __;})
#define min(a, b) ({TYPE _ = (a), __ = (b); _ < __ ? _ : __;})#define maxn 1000005
#define oo 0xFFFFFFF
#define sum(i, j) (s[j] - s[(i) - 1])
#define xxx(k) ({double _ = k; A * _ * _ + B * _ + C;})double A, B, C;
int n, head, tail;
double a[maxn], s[maxn], f[maxn];
struct que{int l, r, x;} q[maxn];void push(int l, int r, int x)
{q[++ tail].x = x;q[tail].l = l, q[tail].r = r;
}int pop_head()
{int ans = q[head + 1].x;if (++ q[head + 1].l > q[head + 1].r) ++ head;return ans;
}void pop_tail()
{if (! -- tail) return;q[tail].r = q[tail + 1].r;
}int main()
{freopen("commando.in", "r", stdin);freopen("commando.out", "w", stdout);scanf("%d%lf%lf%lf", & n, & A, & B, & C);for (int i = 1; i <= n; ++ i)scanf("%lf", & a[i]), s[i] = s[i - 1] + a[i], f[i] = - oo;push(1, n, 0);for (int i = 1; i <= n; ++ i){int j = pop_head();f[i] = f[j] + xxx(sum(j + 1, i));while (head < tail){int l = q[tail].l, r = q[tail].r, x = q[tail].x;if (f[i] + xxx(sum(i + 1, r)) < f[x] + xxx(sum(x + 1, r))) break;if (f[i] + xxx(sum(i + 1, l)) > f[x] + xxx(sum(x + 1, l))) {pop_tail(); continue;}for (int m = l + r >> 1; l < r; m = l + r >> 1)f[i] + xxx(sum(i + 1, m)) > f[x] + xxx(sum(x + 1, m)) ? r = m : l = m + 1;q[tail].r = l - 1, push(l, n, i); break;}if (head == tail) push(i + 1, n, i);}printf("%.0lf\n", f[n]);return 0;
}

[斜率优化] 特别行动队 commando相关推荐

  1. 提高篇 第五部分 动态规划 第6章 斜率优化动态规划

    例1 任务安排(TYVJ1098) [tyvj1098]任务安排(dp)_薇小薇-CSDN博客 Tyvj1098 任务安排_Monster__Yi的博客-CSDN博客 P2365 任务安排 任务安排 ...

  2. 【斜率优化】特别行动队

    特别行动队 [问题描述] 你有一支由n名预备役士兵组成的部队,士兵从1到n编号,要将他们拆分 成若干特别行动队调入战场.出于默契的考虑,同一支特别行动队中队员的编号 应该连续,即为形如(i,i + 1 ...

  3. 浅谈斜率优化(例题特别行动队)

    题目描述 你有一支由nnn名预备役士兵组成的部队,士兵从111到nnn编号,要将他们拆分 成若干特别行动队调入战场.出于默契的考虑,同一支特别行动队中队员的编号应该连续,即为形如(i,i+1,..., ...

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

    题目 题目描述 你有一支由 nn 名预备役士兵组成的部队,士兵从 11 到 nn 编号,你要将他们拆分成若干特别行动队调入战场.出于默契的考虑,同一支特别行动队中队员的编号应该连续,即为形如 (i, ...

  5. 特别行动队-斜率优化

    APIO2010特别行动队 令S为前缀和,那么n方DP: f[i]=max{f[i],f[j]+a*(S[i]-S[j])*(S[i]-S[j])+b*(S[i]-S[j])+c}; 展开,移项得到: ...

  6. [APIO2010]特别行动队——[斜率优化DP]

    [题目描述] 你有一支由 n 名预备役士兵组成的部队,士兵从 1 到 n 编号,要将他们拆分 成若干特别行动队调入战场.出于默契的考虑,同一支特别行动队中队员的编号 应该连续,即为形如(i,i+1,. ...

  7. 「APIO2010」 特别行动队 - 斜率优化Dp

    题目描述 你有一支由nnn名预备役士兵组成的部队,士兵从1到nnn编号,要将他们拆分成若干特别行动队调入战场.出于默契考虑,同一支特别行动队中队员的编号应该连续,即为形如(i,i+1,...,i+k) ...

  8. APIO2010 特别行动队 斜率优化DP算法笔记

    做完此题之后 自己应该算是真正理解了斜率优化DP 根据状态转移方程$f[i]=max(f[j]+ax^2+bx+c),x=sum[i]-sum[j]$ 可以变形为 $f[i]=max((a*sum[j ...

  9. 【bzoj1911-[Apio2010]特别行动队】斜率优化

    [题目描述] 有n个数,分成连续的若干段,每段的分数为a*x^2+b*x+c(a,b,c是给出的常数),其中x为该段的各个数的和.求如何分才能使得各个段的分数的总和最大. [输入格式]  第1行:1个 ...

最新文章

  1. 未能加载文件或程序集“Report.Basic”或它的某一个依赖项。试图加载格式不正确的程序...
  2. 闪耀澳网 跨界新品泸州老窖国窖1573澳网冠军版发布
  3. python 结果写入excel_python中如何将测试结果写入到原有的excel表格(二)
  4. 【Java 并发编程】线程锁机制 ( 线程安全 | 锁机制 | 类锁 | 对象锁 | 轻量级锁 | 重量级锁 )
  5. HTML标签元素的分类
  6. 对广晟有色的数据分析
  7. 如何处理SAP gateway service使用过程中遇到的400 error - invalid key predicate type for guid
  8. Java中的正则表达式–软介绍
  9. Git客户端(Windows系统)的使用(Putty)(转)
  10. PAT (Advanced Level) Practise:1001. A+B Format
  11. [NEHE Couse] 05.3D Objects
  12. linux ssh 双机互信
  13. Atititv2需求文档模板大纲目录 attilax总结
  14. VB/VBA之死,何时休?
  15. crash report for adobe photoshop cc 2019
  16. JavaScript 使用
  17. ccfcsp-20190301小中大-JAVA语言
  18. saltstack 返回mysql_saltstack(返回值存储到Mysql)
  19. centos中文、英文乱码
  20. VS 2010错误提醒: 必需属性“VSInstallDir”缺失或为空 以及 error MSB8008

热门文章

  1. 华为手机nova计算机怎么找过程,华为nova手机拆机全过程 华为nova真机拆解图解教程...
  2. 谷歌浏览器将ssd盘上的缓存目录迁移至机械硬盘
  3. 整数拆分 python_LeetCode 343. 整数拆分 | Python
  4. 恒讯科技报告:2021-2026年泰国数据中心市场机会
  5. VS code snippets
  6. 4G网络要升级成5G,换卡还是换手机?
  7. Word详细教程一(解决word护眼设置,但有些字底色仍是白色的)
  8. 基于深度学习的三维人体姿态估计
  9. 斯蒂夫·乔布斯 与苹果公司
  10. 【中等】和可被K整除的子数组