[APIO2014] 序列分割(斜率优化dp)

problem

luogu-P3648

你正在玩一个关于长度为 nnn 的非负整数序列的游戏。这个游戏中你需要把序列分成 k+1k+1k+1 个非空的块。

为了得到 k+1k+1k+1 块,你需要重复下面的操作 kkk 次:

  • 选择一个有超过一个元素的块(初始时你只有一块,即整个序列)
  • 选择两个相邻元素把这个块从中间分开,得到两个非空的块。
  • 每次操作后你将获得那两个新产生的块的元素和的乘积的分数。

你想要最大化最后的总得分。

输出最后得分以及划分的任一方案。

solution

前提结论:得分与切的先后顺序无关

假设要把 abcabcabc 切成 a∣b∣ca\mid b\mid cabc

  • 先切 a∣bca\mid bcabc,再切 a∣b∣ca\mid b\mid cabcans=a∗(b+c)+b∗c=ab+ac+bcans=a*(b+c)+b*c=ab+ac+bcans=a(b+c)+bc=ab+ac+bc
  • 先切 ab∣cab\mid cabc,再切 a∣b∣ca\mid b\mid cabcans=(a+b)∗c+a∗b=ac+bc+abans=(a+b)*c+a*b=ac+bc+abans=(a+b)c+ab=ac+bc+ab

这样就可以从左到右 dpdpdp 了。记 sumi=∑j=1iaisum_i=\sum_{j=1}^ia_isumi=j=1iai,即元素分数前缀和。

f(i,j):f(i,j):f(i,j):iii 个数切成 jjj 段的最大得分。

f(i,j)=max⁡k<i{f(k,j−1)+sum(k)∗(sum(i)−sum(k))}f(i,j)=\max_{k<i}\Big\{f(k,j-1)+sum(k)*\big(sum(i)-sum(k)\big)\Big\}f(i,j)=maxk<i{f(k,j1)+sum(k)(sum(i)sum(k))}

jjj 只跟 j−1j-1j1 有关,考虑提到最外面循环,内层简写 f(i,j−1)=f(i)f(i,j-1)=f(i)f(i,j1)=f(i)

假设 k1<k2k_1<k_2k1<k2,且 k1k_1k1 决策优于 k2k_2k2

则必定满足:
f(k1)+sumk1∗sumi−sumk12>f(k2)+sumk2∗sumi−sumk22f(k_1)+sum_{k_1}*sum_i-sum_{k_1}^2>f(k_2)+sum_{k_2}*sum_i-sum_{k_2}^2 f(k1)+sumk1sumisumk12>f(k2)+sumk2sumisumk22

f(k1)−sumk12−f(k2)+sumk22>(sumk2−sumk1)sumif(k_1)-sum_{k_1}^2-f(k_2)+sum_{k_2}^2>(sum_{k_2}-sum_{k_1})sum_i f(k1)sumk12f(k2)+sumk22>(sumk2sumk1)sumi

sumsumsum 是前缀和数组,所以 sumk2≥sumk1sum_{k_2}\ge sum_{k_1}sumk2sumk1,具有单调性。
(f(k1)−sumk12)−(f(k2)−sumk22)(−sumk1)−(−sumk2)>sum(i)\frac{\big(f(k_1)-sum_{k_1}^2\big)-\big(f(k_2)-sum_{k_2}^2\big)}{(-sum_{k_1})-(-sum_{k_2})}>sum(i) (sumk1)(sumk2)(f(k1)sumk12)(f(k2)sumk22)>sum(i)
标准斜率优化的式子,因为 O(nk)O(nk)O(nk) 无法再接受一个 log⁡\loglog ,所以我最热爱的李超树就被 pass\text{pass}pass 掉了。

斜率优化想必最头疼的就是用队列维护首尾弹出时的大小于符号的定向问题。

网上一堆凸包图形,对于我这种平面几何感几乎为零的蒟蒻而言简直就是天方夜谭。

所以这里写一种判断方法吧,不保证正确性

  • 队首的弹出很简单,因为上面的斜率优化式子已经化出来了,直接 slope(q[head],q[head+1])slope(q[head],q[head+1])slope(q[head],q[head+1])sum(i)sum(i)sum(i) 比较。

    如果 ≤sum(i)\le sum(i)sum(i) 说明 k2k_2k2 即后者 q[head+1]q[head+1]q[head+1] 更优。

    就需要弹队首。

  • 队尾的弹出较为复杂,考虑的是 slope(q[tail−1],q[tail])slope(q[tail-1],q[tail])slope(q[tail1],q[tail])slope(q[tail],i)slope(q[tail],i)slope(q[tail],i)

    准确而言是考虑 q[tail]q[tail]q[tail] 可不可能做队首。

    那么当现在的队尾在后面某个枚举位置时变成了队首,

    就必须要满足 slope(q[tail−1],q[tail])≤sumpslope(q[tail-1],q[tail])\le sum_pslope(q[tail1],q[tail])sump,这样才能弹出 q[tail−1]q[tail-1]q[tail1]

    • 假设弹队尾的条件是 slope(q[tail−1],q[tail])≤slope(q[tail],i)slope(q[tail-1],q[tail])\le slope(q[tail],i)slope(q[tail1],q[tail])slope(q[tail],i)

      显然存在 slope(q[tail−1],q[tail])≤sump<slope(q[tail],i)slope(q[tail-1],q[tail])\le sum_p<slope(q[tail],i)slope(q[tail1],q[tail])sump<slope(q[tail],i) 的可能性。

      所以这么弹可能把答案取值点给弹出去。

    • 假设弹队尾的条件是 slope(q[tail−1],q[tail])≥slope(q[tail],i)slope(q[tail-1],q[tail])\ge slope(q[tail],i)slope(q[tail1],q[tail])slope(q[tail],i)

      因为 slope(q[tail],i)≤slope(q[tail−1],q[tail])≤sumpslope(q[tail],i)\le slope(q[tail-1],q[tail])\le sum_pslope(q[tail],i)slope(q[tail1],q[tail])sump

      所以 q[tail−1]q[tail-1]q[tail1]q[tail]q[tail]q[tail] 弹出后,马上 q[tail]q[tail]q[tail] 就会被 iii 弹出去。

      那么 q[tail]q[tail]q[tail] 永远都不可能当队首。

    综上,我们确定了队尾判断的符号。

注意:前面的表述据说明 sumisum_isumi 不是严格递增的,存在平台,所以遇到 sumi=sumjsum_i=sum_jsumi=sumj 返回斜率极小值即可。

code

#include <bits/stdc++.h>
using namespace std;
#define int long long
#define maxn 100005
int n, k, d;
int a[maxn], sum[maxn], q[maxn];
int g[maxn][205], f[maxn][205];
double slope( int x, int y ) {if( sum[x] == sum[y] ) return -1e18;return (f[x][d] - sum[x] * sum[x] - f[y][d] + sum[y] * sum[y]) * 1.0 / (sum[y] - sum[x]);
}
void print( int n, int d ) {if( d == 1 ) return;print( g[n][d], d - 1 );printf( "%d ", g[n][d] );
}
signed main() {scanf( "%lld %lld", &n, &k );for( int i = 1;i <= n;i ++ ) scanf( "%lld", &a[i] );for( int i = 1;i <= n;i ++ ) sum[i] = sum[i - 1] + a[i];for( d = 1;d <= k;d ++ ) {int head = 1, tail = 0;for( int i = 1;i <= n;i ++ ) {while( head < tail and slope( q[head], q[head + 1] ) <= sum[i] ) head ++;f[i][d + 1] = f[q[head]][d] + sum[q[head]] * ( sum[i] - sum[q[head]] );g[i][d + 1] = q[head];while( head < tail and slope( q[tail - 1], q[tail] ) >= slope( q[tail], i ) ) tail --;q[++ tail] = i;}}printf( "%lld\n", f[n][d] );print( n, d );return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/316285.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

中间件是什么?在.NET Core中的工作原理又是怎样的呢?

本文出自《从零开始学ASP.NET CORE MVC》推荐文章&#xff1a;ASP.NET Core appsettings.json文件ASP.NET Core 中的中间件(Middleware)在这个视频中&#xff0c;我们将了解&#xff0c;ASP.NET Core 中的中间件是 什么&#xff1f;中间件很重要&#xff0c;尤其是在你想当架构…

P2408 不同子串个数

P2408 不同子串个数 题意&#xff1a; 给你一个长为 n 的字符串&#xff0c;求不同的子串的个数。 我们定义两个子串不同&#xff0c;当且仅当有这两个子串长度不一样或者长度一样且有任意一位不一样。 子串的定义&#xff1a;原字符串中连续的一段字符组成的字符串。 题解…

[SDOI2016] 生成魔咒(后缀数组SA + st表 + set)动态不同子串个数

problem luogu-P4070 魔咒串由许多魔咒字符组成&#xff0c;魔咒字符可以用数字表示。例如可以将魔咒字符 1,21,21,2 拼凑起来形成一个魔咒串 [1,2][1,2][1,2]。 一个魔咒串 S 的非空字串被称为魔咒串 S 的生成魔咒。 例如 S[1,2,1]S[1,2,1]S[1,2,1] 时&#xff0c;它的生成…

P4248 [AHOI2013]差异

P4248 [AHOI2013]差异 题意&#xff1a; ∑1≤i<j≤nlen(Ti)len(Tj)−2∗lcp(Ti,Tj)\sum_{1\leq i<j\leq n}len(T_{i})len(T_{j})-2*lcp(T_{i},T_{j})∑1≤i<j≤n​len(Ti​)len(Tj​)−2∗lcp(Ti​,Tj​) 题解&#xff1a; ∑1≤i<j≤nlen(Ti)len(Tj)\sum_{1\le…

从高德采集最新的省市区三级坐标和行政区域边界,用js在浏览器中运行

本文描述的是对国家统计局于2019-01-31发布的《2018年统计用区划代码和城乡划分代码(截止2018年10月31日)》中省市区三级的坐标和行政区域边界的采集。本文更新&#xff08;移步查阅&#xff09;&#xff1a;19-04-15 新采集了2018的省市区三级的坐标和行政区域边界数据csv格式…

[JSOI2016] 最佳团体(0/1分数规划 + 树形dp)

problem luogu-P4322 solution 假设每个人是否被招募&#xff0c;用 xi{0,1}x_i\{0,1\}xi​{0,1} 代替&#xff0c;max⁡∑pi∗xi∑si∗xi\max\frac{\sum p_i*x_i}{\sum s_i*x_i}max∑si​∗xi​∑pi​∗xi​​。 0/10/10/1 分数规划标准式子。 二分答案 ans∑pi∗xi∑si∗…

Display Substring

Display Substring 题意&#xff1a; 一个长度为n的字符串&#xff0c;每个字符有自己的价值&#xff0c;求第k小价值的不重复子串价值 题解&#xff1a; 首先众所周知&#xff0c;所有子串都可以用后缀的前缀来表示&#xff0c;这就和后缀数组扯上关系了 我们可以直接二分…

使用 DotNet CLI 创建自定义的 WPF 项目模板

描述当我们安装完 DotNetCore 3.0 版本的 SDK 后&#xff0c;我们就可以创建基于 DotNetCore 的 WPF 项目模板&#xff0c;通过如下 CLI 可以方便快捷的创建并运行我们的项目&#xff1a;Copydotnet new wpf -n WpfAppcd WpfAppdotnet restoredotnet run做过 WPF 开发的朋友都知…

[省选联考 2020 A/B 卷] 信号传递(状压dp + 卡空间)

problem luogu-P6622 一条道路上从左至右排列着 mmm 个信号站&#xff0c;初始时从左至右依次编号为 1,2,…,m1,2,\dots,m1,2,…,m&#xff0c;相邻信号站之间相隔 111 单位长度。 每个信号站只能往它右侧的任意信号站传输信号&#xff08;称为普通传递&#xff09;&#xf…

SP687 REPEATS - Repeats(暂时不会)

SP687 REPEATS - Repeats 题意&#xff1a; 给定字符串&#xff0c;求重复次数最多的连续重复子串 题解&#xff1a; 论文题&#xff0c;暂时不会&#xff0c;搞不清楚原理 代码&#xff1a;

[翻译] ASP.NET Core 利用 Docker、ElasticSearch、Kibana 来记录日志

一步一步指导您使用 ElasticSearch, Kibana, ASP.NET Core 2.1 和 Docker 来记录日志在本教程中&#xff0c;我将向您展示如何启动和运行 ElasticSearch&#xff0c;Kibana 和 ASP.NET Core 2.1在开始之前&#xff0c;让我们来看看 ElasticSearch&#xff0c;Kibana 和 Serilog…

[省选联考 2020 A 卷] 作业题(欧拉反演 + 矩阵树定理 + 高斯消元)

problem luogu-P6624 小 W 刚刚在离散数学课学习了生成树的知识&#xff1a;一个无向图 G(V,E)G(V,E)G(V,E) 的生成树 TTT 为边集 EEE 的一个大小为 ∣V∣−1|V|-1∣V∣−1 的子集&#xff0c;且保证 TTT 的生成子图在 GGG 中连通。 小 W 在做今天的作业时被这样一道题目难住…

P4070 [SDOI2016]生成魔咒

P4070 [SDOI2016]生成魔咒 题意&#xff1a; 有n个字符xi&#xff0c;每次在S的末尾加入一个字符&#xff0c;(一开始S为空)&#xff0c;每次加入xi后的不相同字串有多少个 题解&#xff1a; 做这个题首先要会后缀数组P3809 【模板】后缀排序&#xff0c;还要知道不同的子串…

【学习笔记】WQS二分详解及常见理解误区解释

文章目录应用分析算法分析WQS二分精髓的两点细节&#xff08;博客重点&#xff01;&#xff09;真题分析[国家集训队]Tree Ⅰ忘情星际广播网上很多博客写得模模糊糊的&#xff0c;对我这个新手可是一点都不友好。 昨天一天都在研究这个东西&#xff0c;分享一下自己的拙见。 百…

ASP.NET Core中HTTP管道和中间件的二三事

本文出自《从零开始学ASP.NET CORE MVC》推荐文章&#xff1a;中间件是什么&#xff1f;在.NET Core中的工作原理又是怎样的呢&#xff1f;配置ASP.NET Core请求(Request)处理管道在本视频中&#xff0c;我们将讨论使用中间件组件为asp.net core 应用程序配置请求处理管道。作为…

Codeforces Round #737 (Div. 2)

Codeforces Round #737 (Div. 2) 题号题目知识点AEzzat and Two Subsequences思维&#xff08;略&#xff09;BMoamen and k-subarrays思维(略)CMoamen and XOR二进制DEzzat and Grid线段树思维EAssiut Chess

非平凡回路(bfs)

problem 题目描述 给定一张 nnn 个点的无向图&#xff0c;定义经过一个点 uuu 的非平凡回路为一条从 uuu 出发回到 uuu 的路径&#xff0c;并且至少包含一个简单环。 对于每个点求出经过它的最小非平凡回路长度 lll。 考虑到这个问题很困难&#xff0c;因此你只需要求出 ⌈…

cf1557 C. Moamen and XOR

cf1557 C. Moamen and XOR 题意&#xff1a; 一个n位数&#xff0c;每一位小于2k2^k2k,如果a1&a2&…an>a1⊕a2…⊕an,则获胜 现在给你n和k&#xff0c;问能构造多少个序列是获胜的 题解&#xff1a; 奇偶分类二进制考虑 我们现在认为每个数的第k位都是1 如果n为…

.Net Core Razor 预编译,动态编译,混合编译

预编译预编译是ASP .Net Core的默认方式。在发布时&#xff0c;默认会将系统中的所有Razor视图进行预编译。编译好的视图DLL统一命名为 xxx.PrecompiledViews.dll 或者 xxx.Views.dll动态编译将项目整个配置成动态编译很简单&#xff0c;添加一个配置项目MvcRazorCompileOnPubl…

[CodeForces gym 101630 J] 过路费(最短路)

problem 给定一张图 nnn 个点 mmm 条边&#xff0c;并给定阈值 kkk&#xff0c;以及起终点 s,ts,ts,t。 然后每条边经过都需要支付 www 的花费&#xff0c;形如 (u,v,w)(u,v,w)(u,v,w) 格式给出。 求 s→ts\rightarrow ts→t 的最小花费。 最小花费定义如下&#xff1a; 如…