当前位置: 首页 > news >正文

斜率优化dp复习笔记

P3648 [APIO2014] 序列分割

将序列分割成 \(k+1\) 个部分,每个部分的元素 \(\geq 1\),然后假设一个块你要分成两个块,代价为分成后两个块里面的元素和的乘积,问你怎么才能使代价最大,并输出方案(SPJ)。

题目分析

注意到顺序是无关紧要的:

若一个块 \(sum\) 要从 \(i,j\) 这里下手(分成三段的和 \(a,b,c\)),顺序所导致的有:

  • 先从 \(i\) 砍,代价为 \(a(b+c)+bc=ab+ac+bc\)
  • 先从 \(j\) 砍,代价为 \((a+b)c+ab=ab+ac+bc\)

两者相等,顺序无用。

故设 \(f_{i,j}\) 表示前 \(i\) 个部分切 \(j\) 次,那么有:

\[f_{i,j}=\max_{l\in[0,i-1]} f_{l,j-1}+sum_l\times(sum_i-sum_l) \]

顺序无关,所以我先在 \(i\) 切,然后再切前面的。

考虑斜率优化,对于 \(j<l\)\(j\)\(l\) 更优,并设 \(f_{x,j-1}=f_x\)

有:

\[f_j+sum_isum_j-sum_j^2>f_l+sum_isum_l-sum_l^2 \Rightarrow \frac{(f_j-sum_j^2)-(sum_l-sum_l^2)}{-sum_j-(-sum_l)}>sum_i \]

那么点集就是 \((-sum_x,f_x-sum_x^2)\)

那么对于当前点 \(i\),所有斜率 \(\leq sum_i\) 的都不可行。

然后队头就是最优决策点,为什么呢?因为对于 \(j<l\) 满足即可,显然是第一个。

也就是直接去维护斜率递增。

现在要把 \(i\) 也添加进来。那么我们维护斜率递增即可。

代码

时间复杂度 \(\mathcal{O}(nk)\),代码如下:

#include <iostream>
#include <cstdio>
#include <stdlib.h>
#include <cstring>
#include <stdlib.h>
#include <vector>
#include <deque>
#define int long long
#define N 100005
#define K 205
using namespace std;
int pre[N][K],a[N],sum[N],f[N],g[N];
int x(int id) {return -sum[id];}
int y(int id) {return g[id] - sum[id] * sum[id];}
double slope(int fir,int sec) {if (x(fir) == x(sec)) return -1e18;return 1.0 * (y(fir) - y(sec)) / (1.0 * (x(fir) - x(sec)));
}
int q[N],head,tail;
signed main(){int n,k;cin >> n >> k;// k ++;for (int i = 1;i <= n;i ++) scanf("%lld",&a[i]),sum[i] = sum[i - 1] + a[i];// for (int i = 0;i <= n;i ++)//     for (int j = 0;j <= n;j ++) f[i][j] = -1e18;// f[0][0] = 0;// for (int i = 1;i <= n;i ++)//     for (int j = 1;j <= min(i,k);j ++)//         for (int t = 0;t < i;t ++)//             if (f[t][j - 1] + sum[t] * (sum[i] - sum[t]) > f[i][j])//                 f[i][j] = f[t][j - 1] + sum[t] * (sum[i] - sum[t]),pre[i][j] = t;// printf("%lld\n",f[n][k]);// int now = n;// for (int j = k;j > 1;j --) printf("%lld ",pre[now][j]),now = pre[now][j];for (int t = 1;t <= k;t ++) {for (int i = 1;i <= n;i ++) g[i] = f[i];tail = 0;head = 1;// q[++tail] = 0;for (int i = 1;i <= n;i ++) {while(tail > head && slope(q[head],q[head + 1]) <= sum[i]) head ++;f[i] = 0;if (head <= tail) {pre[i][t] = q[head];f[i] = g[q[head]] + sum[q[head]] * (sum[i] - sum[q[head]]);}while(tail > head && slope(q[tail - 1],q[tail]) >= slope(q[tail],i)) tail --;q[++tail] = i;}}printf("%lld\n",f[n]);int now = n;for (int j = k;j >= 1;j --) printf("%lld ",pre[now][j]),now = pre[now][j];return 0;
}
http://www.gsyq.cn/news/16063.html

相关文章:

  • 掌握形式验证,护航芯片安全
  • 2025橡胶软接头厂家最新企业品牌推荐排行榜,法兰橡胶软接头,可曲挠,挠性,KXT,耐油,EPDM,耐腐蚀,三元乙丙橡胶软接头,橡胶柔性软接头公司推荐!
  • 整体二分笔记
  • 基于Python+Vue开发的母婴商城管理系统源码+运行步骤
  • 机器学习Day5-模型诊断 - 详解
  • Probabilistic method小记
  • 数据生成方法初步调研
  • 深入解析:一起学Spring AI:核心概念
  • 做题记录(Oct.)
  • 生成式AI改进极端多标签分类技术
  • 实用指南:蓝桥杯_DS18B20温度传感器---新手入门级别超级详细解析
  • 越秀凭一己之力打破了行业天花板 - 智慧园区
  • 洛谷P9676 [ICPC 2022 Jinan R] Skills
  • 微信小程序(uniapp)搭建腾讯云 IM 消息撤回
  • 实用指南:苍茫命令行:linux模拟实现,书写微型bash
  • CF2149题解
  • 月球尘埃电解技术实现资源就地利用
  • 漏洞赏金计划公开后的三个阶段与应对策略
  • Python 在教育与科研中的应用与价值
  • 谈谈redis的热key问题如何解决
  • 玩转树莓派屏幕之二:自定义屏幕显示
  • 欧易OKX‌交易所注册全流程指南
  • 神秘专题训练之老题补做
  • 全球 whk 水平下降 998244353 倍,而你不变
  • 202510做题记录
  • 全球 wkh 水平下降 998244353 倍,而你不变
  • 哈希简单解说
  • 前端学习教程-VIte整合ECharts
  • Atcoder Beginner Contest 426 A-D 题解
  • mtgsig