很显然有一个暴力 \(dp\),令 \(dp_{i, j}\) 表示最后一次划分在 \(i\) 上次划分在 \(j\) 的最小花费,令 \(S_i = \sum\limits_{j = 1} ^ i a_j\)。那么有转移:

\[dp_{i, j} = \min\{dp_{j, k} + (S_i - S_j) ^ 2\}(S_i - S_j \ge S_j - S_k)
\]

可以发现 \(dp_{j, k}\) 的值是和 \(i\) 无关的,只是 \(k\) 的取值范围和 \(i\) 有关,那么我们只需要知道 \(k\) 的取值范围再取这个范围内的最小值即可。将后面那个条件移项可得 \(S_k \ge 2 \times S_j - S_i\),因此 \(k\) 的取值范围应该在 \(2 \times S_j - S_i \sim j - 1\),而当 \(j\) 固定时,因为 \(S_i\) 随着 \(i\) 的增大单调递增,所以 \(k\) 能取到的下界不断减小,于是我们可以考虑在 \(i\) 的同时维护每个 \(j\) 的下界以及当前能取到的最小 \(dp_{j, k}\) 这样均摊复杂度就是 \(O(n ^ 2)\) 的了。

rep(i, 1, n) dp[i][0] = sum[i] * sum[i], p[i] = i - 1, mx[i] = inf;
rep(i, 2, n){
rep(j, 1, i - 1){
while(p[j] >= 0 && sum[p[j]] >= 2 * sum[j] - sum[i]) mx[j] = min(mx[j], dp[j][p[j]]), --p[j];
if(p[j] < j - 1) ++p[j];
if(mx[j] != inf) dp[i][j] = mx[j] + (sum[i] - sum[j]) * (sum[i] - sum[j]);
}
}
rep(i, 0, n - 1) ans = min(ans, dp[n][i]);
printf("%lld", ans);
return 0;

如果这个 \(dp\) 不能压缩状态是显然无法优化的,但为了保证题目中的条件,我们根本无法压缩状态,下面一个常见的手段就是可以打个决策转移的表。可以发现我们每次转移 \(j \rightarrow i\) 都是选择了一个最大的能满足条件的 \(k\) 从 \(dp_{j, k} \rightarrow dp_{i, j}\),并且可以发现当 \(j\) 越大时 \(dp_{i, j}\) 越大。这样换句话来说就是每次我们让最后一段尽可能选择小的是更优的,实际上因为我们有 \((a + b) ^ 2 > a ^ 2 + b ^ 2\) 因此我们要尽可能多分段,如果我们每次选择最小的一段,不仅能够分更多的段,并且还能让后面尽可能分的段更多,并且能让当前的贡献更小,所以这样做一定是更优的。针对这个贪心,我们可以令 \(dp_i\) 表示当前划分到以 \(i\) 结尾的段的最小花费,令 \(p_i\) 表示 \(i\) 是由哪里转移来的,那么每次转移就要找到一个最大 \(j\) 满足 \(S_i - S_j \ge S_j - S_{p_j}\) 移项可得 \(S_i \ge 2 \times S_j - S_{p_j}\),我们大可以使用线段树二分出左边第一个比某个数大的位置,但实际上这里还有个 \(O(n)\) 做法。可以发现因为 \(S_i\) 是单调递增的,因此我们之前能够选择的 \(j\) 随着 \(i\) 的增大一定是还能继续选的。因此我们可以维护一个类似单调队列的东西,在队列中 \(2 \times S_j - S_{p_j}\) 单调递增,每次我新加入一个元素,从队尾一直开始弹出知道这个 \(2 \times S_{q_t} - S_{p_{q_t}} < 2 \times S_j - S_{p_j}\) 为止,那么这样我们获得的每个值的位置都将是当前最靠右的点,并且由于 \(S_i\) 在不断单调递增,我们只需要每次不断移动队尾找到队列中最后一个 \(\le S_i\) 的元素即可。

dp[1] = a[1] * a[1], h = 1, t = 2, q[1] = 0, q[2] = 1;
rep(i, 2, n){
while(h <= t && 2 * sum[q[h]] - sum[p[q[h]]] <= sum[i]) ++h;
--h, p[i] = q[h];
dp[i] = dp[p[i]] + (sum[i] - sum[p[i]]) * (sum[i] - sum[p[i]]);
while(h <= t && 2 * sum[i] - sum[p[i]] <= 2 * sum[q[t]] - sum[p[q[t]]]) --t;
q[++t] = i;
}
printf("%lld", dp[n]);

最后那 \(12\) 分需要使用高精度,根据我们的流程可以看出实际上我们不需要记录 \(dp\) 数组,只需要记录之前的 \(p\) 即可,最后我们只需要不断往下迭代加上每一段的值即可,我的高精太丑了(其实是写的 \(\_\_int128\))就不贴了。

CSP2019 Day2T2 划分的更多相关文章

  1. CSP2019 D2T2 划分 (单调队列DP)

    题目 洛谷传送门 题解 就是这道题搞我退役考场上写了n^2 64分,结果爆成8-12分.直接GG. 考场上想到正解的写法被自己否决了 题解传送门(看到这道送我退役的题目⑧太想写题解) 六行O(n2)O ...

  2. 【CSP2019】题解合集

    诈个尸 先挖坑 虽然连去都没去但还是想做做 今年貌似比去年还毒瘤啊... yrx.hjw都进了省队线tql orz (myh:没AK真丢脸 Day1T1 格雷码 Day1T2 括号树 Day1T3 树 ...

  3. CSP-S 2019 Solution

    Day1-T1 格雷码(code) 格雷码是一种特殊的 \(n\) 位二进制串排列法,要求相邻的两个二进制串恰好有一位不同,环状相邻. 生成方法: \(1\) 位格雷码由两个 \(1\) 位的二进制串 ...

  4. CSP2019 S2滚粗记

    最好分数:100+20+10+64+64+55 最坏分数:100+20+10+64+36+55 咕咕数据分数:100+25+10+64+60+55 CCF官方: 100+35+10+64+36+55= ...

  5. CSP2019题解

    CSP2019题解 格雷码 按照生成的规则模拟一下即可. 代码 括号树 看到括号匹配首先想到用栈,然后又在树上就可以想到可追溯化栈. 令\(a_i=1\)表示\(i\)号节点上的括号为(,否则为), ...

  6. CSP2019 题解

    CSP2019 题解 D1T1 格雷码(code) 题目传送门 https://loj.ac/problem/3208 题解 按照题意模拟就可以了. 对于第 \(i\) 位,如果 \(k \geq 2 ...

  7. [LeetCode] Partition List 划分链表

    Given a linked list and a value x, partition it such that all nodes less than x come before nodes gr ...

  8. SWMM模型子汇水区划分的几种方法

    子汇水区的划分是SWMM模型建模的主要步骤之一,划分的好坏对结果精度有比较大的影响.概括来讲,子汇水区的划分有以下几种思路: (1)根据管网走向.建筑物和街道分布,直接人工划分子汇水区.这个方法适用于 ...

  9. 等价类划分方法的应用(jsp)

    [问题描述] 在三个文本框中输入字符串,要求均为1到6个英文字符或数字,按submit提交. [划分等价类] 条件1: 字符合法; 条件2: 输入1长度合法; 条件3: 输入2长度合法: 条件4: 输 ...

随机推荐

  1. Django项目部署到Apache服务器上

    之前写了把Django部署到XAMPP上,但是有bug,翻apache日志的时候发现会无法import _ssl,然后我就怒而直接装apache2了 配置方法大约和这篇文章差不多 安装必要的包 sud ...

  2. CS5266 Type-C转HDMI+PD3.0+USB3.0 三合一拓展坞电路设计

    CS5266 Type-C转HDMI+PD3.0+USB3.0 三合一拓展坞电路设计 CS5266是一款带PD3.0快充 Type-C转HDMI 4K30HZ音视频转换芯片.CS5266支持PD3.0 ...

  3. 编写Java程序,使用Swing事件处理机制实现用户登录和英雄信息显示

    返回本章节 返回作业目录 需求说明: 使用Swing事件处理机制实现用户登录和英雄信息显示 实现思路: 创建LoginView类,该类用于显示登录界面,为登录按钮添加ActionListener事件, ...

  4. 初识python 之 爬虫:使用正则表达式爬取“糗事百科 - 文字版”网页数据

    初识python 之 爬虫:使用正则表达式爬取"古诗文"网页数据 的兄弟篇. 详细代码如下: #!/user/bin env python # author:Simple-Sir ...

  5. 初识python 之 爬虫:使用正则表达式爬取“古诗文”网页数据

    通过requests.re(正则表达式) 爬取"古诗文"网页数据. 详细代码如下: #!/user/bin env python # author:Simple-Sir # tim ...

  6. Windows 重装系统,配置 WSL,美化终端,部署 WebDAV 服务器,并备份系统分区

    最新博客文章链接 最近发现我 Windows11 上的 WSL 打不开了,一直提示我虚拟化功能没有打开,但我看了下配置,发现虚拟化功能其实是开着的.然后试了各种方法,重装了好几次系统,我一个软件一个软 ...

  7. 关于Vue中根组件与组件树的理解

    在观看了b站的关于Vue3的教学视频后,对Vue的根组件与组件树进行简单的总结下 一.实例化Vue应用 // 此时,app就是一个Vue应用的实例,或者说是一个对象 const app = Vue.c ...

  8. Vulnhub系列:chili

    0x01 靶机信息 靶机:chili难度:简单下载:https://www.vulnhub.com/entry/chili-1,558/ 靶机描述: 0x02 信息收集 nmap扫描存活主机确定靶场i ...

  9. 《剑指offer》面试题15. 二进制中1的个数

    问题描述 请实现一个函数,输入一个整数,输出该数二进制表示中 1 的个数.例如,把 9 表示成二进制是 1001,有 2 位是 1.因此,如果输入 9,则该函数输出 2. 示例 1: 输入:00000 ...

  10. sqoop如何指定pg库的模式

    摘要:sqoop如何指定pg库的模式? 本文分享自华为云社区<[Hadoop]关于Sqoop导出数据到postgresql时schema的设置问题>,作者:Copy工程师 . 说明 使用s ...