[luogu3628][bzoj1911][APIO2010]特别行动队【动态规划+斜率优化DP】
题目描述
给你一个数列,让你将这个数列分成若干段,使其每一段的和的\(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】的更多相关文章
- BZOJ1911 [Apio2010]特别行动队 - 动态规划 - 斜率优化
欢迎访问~原文出处——博客园-zhouzhendong 去博客园看该题解 题目传送门 UPD(2018-04-01):用Latex重打了公式…… 题意概括 把一个整数序列划分成任意连续的段,使得划分出 ...
- 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])+ ...
- [bzoj1911][Apio2010特别行动队] (动态规划+斜率优化)
Description Input Output Sample Input - - Sample Output HINT Solution 斜率优化动态规划 首先易得出这样的一个朴素状态转移方程 f[ ...
- BZOJ1911 [Apio2010]特别行动队 【斜率优化】
1911: [Apio2010]特别行动队 Time Limit: 4 Sec Memory Limit: 64 MB Submit: 5005 Solved: 2455 [Submit][Sta ...
- bzoj 1911 [Apio2010]特别行动队(斜率优化+DP)
1911: [Apio2010]特别行动队 Time Limit: 4 Sec Memory Limit: 64 MBSubmit: 3191 Solved: 1450[Submit][Statu ...
- 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]= ...
- 【BZOJ】1911: [Apio2010]特别行动队(斜率优化dp)
题目 传送门:QWQ 分析 用$ dp[i] $ 表示前 i 个人组成的战斗力之和 然后显然$ dp[i]=Max ( dp[j]+a*(sum[i]-sum[j])^2+b*(sum[i]-sum ...
- _bzoj1911 [Apio2010]特别行动队【斜率优化dp】
传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=1911 裸的斜率优化dp. #include <cstdio> const int ...
- bzoj 1911: [Apio2010]特别行动队【斜率优化dp】
仔细想想好像没学过斜率优化.. 很容易推出状态转移方程\( f[i]=max{f[j]+a(s[i]-s[j])^2+b(s[i]-s[j])+c} \) 然后考虑j的选取,如果选j优于选k,那么: ...
- 【BZOJ 1191】 [Apio2010]特别行动队 (斜率优化)
dsy1911: [Apio2010]特别行动队 [题目描述] 有n个数,分成连续的若干段,每段的分数为a*x^2+b*x+c(a,b,c是给出的常数),其中x为该段的各个数的和.求如何分才能使得各个 ...
随机推荐
- mysql数据从windows导出,再导入到linux
从windows导出时,要注意字符集最好和linux的一致,如linux字符集一般为utf8,则导出时可以加上参数--default-character-set=utf8指定字符集,然后导入到linu ...
- winform自定义控件开发
1.添加控件属性 //添加私有的控件属性 private string djm;//单据名 //添加属性描述 [Browsable(true)] [Description("djm" ...
- 测试python最大递归层次
转自:https://www.cnblogs.com/xiongdashuai/p/6243372.html python默认的最大递归层数: 运行环境:Windows 7,x64python环境:p ...
- java Date时间的各种转换方式和Mysql存时间类型字段的分析
一:各种Date之间的转换方法 public class TimeTest { public static void main(String[] args) { Date date = new Dat ...
- CMake--变量
1.一般变量 1)CMake变量引用的方式 使用${}进行变量的引用.例如: ${PROJECT_NAME} #返回项目名称 在 IF 等语句中,是直接使用变量名而不通过${}取值. 2)cmake自 ...
- git fetch 和git pull 的差别
1.git fetch 相当于是从远程获取最新到本地,不会自动merge,如下指令: git fetch orgin master //将远程仓库的master分支下载到本地当前branch中 git ...
- CRM/PLM/SCM/MES与ERP的联系与区别
企业通过专设信息机构.信息主管,配备适应现代企业管理运营要求的自动化.智能化.高技术硬件.软件.设备.设施,建立包括网络.数据库和各类信息管理系统在内的工作平台,提高企业经营管理效率的发展模式. 那么 ...
- mysql 清除大数据表单
背景:mysql数据库中有个日志表记录高达800多万,影响了mysql的正常业务访问,现需要清理三个月之前的所有数据,大概600多万(大概13G) 方法一:传统delete from xxx,传统,普 ...
- python设计模式第二十天【迭代器模式】
1.不使用迭代器出现的问题 (1)容器承担了太多的功能,一方面提供添加和删除等功能,还需提供遍历访问功能 (2)在容器访问遍历过程中,需要保存遍历状态,当和元素的添加和删除混杂在一起时,容易引起混乱 ...
- delphi中如何实现DBGrid中的两列数据想减并存入另一列
可参考下面的例子: 数据自动计算的实现:“金额”是由“单价”和“工程量”相乘直接得来的,勿需人工输入. 这可在“数据源构件”的onupdatedata例程添加如下代码实现: procedure T ...