Codeforces-1667 B: Optimal Partition

题目传送门:Codeforces-1667 B

题目

题目截图

样例描述

题目大意

  给定一个长度为 nnn 的数组 aaa,希望将 aaa 切成几个连续的段。对于给定 l⋯rl \cdots rl⋯r 的一段连续子数组 al,al+1,⋯,ara_l, a_{l+1},\cdots,a_ral​,al+1​,⋯,ar​,令 s=al+al+1+⋯+ars=a_l+a_{l+1}+\cdots+a_rs=al​+al+1​+⋯+ar​,则该段的价值为:
vl⋯r={(r−l+1)ifs>0,0ifs=0−(r−l+1)ifs<0v_{l\cdots r} = \left\{ \begin{array}{ll} (r-l+1) \; if \; s > 0, \\ 0 \; if \; s = 0 \\ -(r-l+1) \; if \; s < 0 \end{array} \right. vl⋯r​=⎩⎨⎧​(r−l+1)ifs>0,0ifs=0−(r−l+1)ifs<0​
  问将该数组切成几个非空连续的段后,所能获得的最大价值总和是多少。

题目解析

  这道题很有趣,首先根据题目,不难判断出这是一个 dpdpdp 问题。设 dpidp_idpi​ 代表从 1⋯i1\cdots i1⋯i 能够得到的最大价值总和,那么 dpi=max⁡j{dpj+vj+1⋯i}dp_i = \max_j \{dp_j + v_{j+1 \cdots i}\}dpi​=maxj​{dpj​+vj+1⋯i​},尽管 vvv 值我们可以靠预处理前缀和 O(1)O(1)O(1) 得到,但是找 iii 的过程仍然是 O(n2)O(n^2)O(n2) 的,这样是过不了这道题的。
  考虑如何更快地进行解题,首先从这个条件入手,看题解发现,当一段长度大于 111 的区间 s>0s > 0s>0 时,它加入答案才能获得更大的收益,否则,我们都可以通过拆的方式将它拆成长度为 111 的几个小段。因为 s<0s < 0s<0 时,我们将整个区间再进行拆分,那么得到的结果如果有 s>0s > 0s>0 的部分,则结果更优,否则结果也不会更差。如果 s=0s = 0s=0 的话,我们也可以对整个区间进行拆分,若长度是偶数,那么可以分成左右两部分,结果不会更差(sss 要么都是 000,要么一正一负;若长度为奇数,则暂时将该段分成左、中(长度为 111)、右三部分,若左或右的 s<0s < 0s<0,那么将其分成两段(左,中右)或(左中,右)两部分的话,结果会更好。其余情况可以直接拆成(左、中、右)三部分,结果不会更差。因此最后长度大于 111 的子段,我们只需要计算 s>0s > 0s>0 的,其余情况只计算长度为 111 的即可。
  我们考虑如何选取子段 s>0s > 0s>0 的区间,首先设 pip_ipi​ 为代表 a1+a2+⋯aia_1+a_2+\cdots a_ia1​+a2​+⋯ai​ 的前缀和。若我们可以对前缀和进行排序,当我们已知当前位置 iii 的前缀和排位 ordiord_iordi​ 时,我们可以通过查找前缀和比其小的段 1⋯j1\cdots j1⋯j(ordj<ordiord_j < ord_iordj​<ordi​),且 j<ij<ij<i 进行更新。这样我们可以保证 j+1⋯ij+1 \cdots ij+1⋯i 区间的 vvv 值是正的,我们可以直接使用 i−ji-ji−j 表示这一段的价值。
  但尽管这样能够保证正值,但仍然需要查找 jjj,根源在于统计 j+1⋯ij+1 \cdots ij+1⋯i 的价值需要同时用到两次更新的坐标位置。但其实我们可以把+i,−j+i,-j+i,−j 这两件事情分开做,若我们每次找最大的 dpj−jdp_j - jdpj​−j,那么在更新 iii 时,我们可以直接将该结果 +i+i+i 便变成了 dpj+i−jdp_j + i - jdpj​+i−j,这样我们就可以分开统计,直接使用树状数组找最大的 dpj−jdp_j - jdpj​−j 就可以省去那一次找 jjj 的遍历,使得总体复杂度变为 O(nlog⁡n)O(n \log n)O(nlogn)。
  值得注意的是排序时,对于前缀和相等的情况,我们要把位置大的放前面,这样我们更新的时候就不会使用位置小的去更新位置大的了(此时该段的总价值为 000,我们更新的时候是直接 +i,−j+i, -j+i,−j 的操作,没有考虑 000 的情况,会导致错误答案,而实际上根据第二段的分析,价值为 000 我们是不该考虑的)。以及要考虑没有分段的情况,即当前位置 iii 的前缀和大于 000,此时最大价值总和就是 iii。

Code

#include <bits/stdc++.h>
using namespace std;typedef long long LL;
const int maxn = 5e5 + 7;
int a[maxn], f[maxn], dp[maxn], ord[maxn], n;
LL p[maxn];
const int rinf = -0x7fffffff;int lowbit(int x) { return (x & -x); }
void update(int x, int v) {while(x <= n) {f[x] = max(f[x], v);x += lowbit(x);}
}
int query(int x) {int ans = rinf;while(x > 0) {ans = max(f[x], ans);x -= lowbit(x);}return ans;
}int main() {int T;cin >> T;while(T--) {cin >> n;for(int i=1; i<=n; ++i) f[i] = rinf;vector<pair<LL, int> > pre;for(int i=1; i<=n; ++i) {cin >> a[i]; p[i] = p[i-1] + a[i]; pre.push_back(make_pair(p[i], -i));}sort(pre.begin(), pre.end());for(int i=1; i<=n; ++i) ord[-pre[i-1].second] = i;for(int i=1; i<=n; ++i) {dp[i] = dp[i-1] + (a[i] > 0?1:(a[i] < 0? -1: 0));dp[i] = max(dp[i], query(ord[i]) + i);if(p[i] > 0) dp[i] = i;update(ord[i], dp[i] - i);}cout << dp[n] << endl;p[0] = 0; dp[0] = 0;}return 0;
}

Codeforces-1667: B Optimal Partition相关推荐

  1. CF 1667B Optimal Partition

    https://codeforces.com/problemset/problem/1667/B

  2. 【CodeForces - 1038B 】Non-Coprime Partition (构造,数组特征)

    题干: Find out if it is possible to partition the first nn positive integers into two non-empty disjoi ...

  3. Educational Codeforces Round 39 A Partition

    传送门 分治就好了,哈哈大于小于0的数据分开算 #include <bits/stdc++.h> using namespace std; typedef long long ll ; t ...

  4. Yet Another Array Partitioning Task CodeForces - 1114B(思维)

    An array b is called to be a subarray of a if it forms a continuous subsequence of a, that is, if it ...

  5. Boring Partition(CF-239D)

    Problem Description This problem is the most boring one you've ever seen. Given a sequence of intege ...

  6. Codeforces Round #783 (Div. 2) A-F

    A.Direction Change 讨论一下每种移动的情况即可.先交替,然后再走多的. 走多的过程需要交替在其他方向移动. #include <iostream> #include &l ...

  7. Codeforces Round 783 补题

    目录 官网链接 div2 C Make it Increasing div1 B Optimal Partition C Half Queen Cover D Edge Elimination E C ...

  8. codeforces每日5题(均1500)-第二十一天

    Walking Robot 题面翻译 Description 在一个数轴上,有一个机器人要从 x=0x = 0x=0 处移动到 x=nx = nx=n 处.机器人身上有两种电池,第一种是普通电池,第二 ...

  9. codeforces 1500分题部分题解(1249c2 770a 1264a 1253c 114b)

    C2. Good Numbers (hard version) 注意 3x 意思是 3^x time limit per test2 seconds memory limit per test256 ...

最新文章

  1. 从零开始一起学习SLAM | SLAM有什么用?
  2. 基本概念_程序员基本功——链表的基本概念
  3. 火狐渗透测试浏览器_微软、火狐浏览器、Opera浏览器等主流平台纷纷布局IPFS:大势所趋...
  4. read write spinlock
  5. cocos2d-x游戏实例(24)-简易动作游戏(2)
  6. 【模板】可持久化并查集
  7. Visual Studio 2010旗舰版在安装Windows Phone 7 SDK后项目模版里没有Windows Phone 项目解决办法...
  8. vba 指定列后插入列_Excle中的VBA介绍分享
  9. 批处理延迟sleep应用
  10. 潭州课堂25班:Ph201805201 并发(非阻塞,epoll) 第十课 (课堂笔记)
  11. 计算机偏门术语,没听说过 WinXP偏门应用技巧四则
  12. java jbpm工作流_JBPM工作流
  13. android 获取软件签名,获取Android应用签名
  14. 重庆“易法院”上线 民众足不出户参与诉讼全过程
  15. linux下的串口编程
  16. 使用pscp命令将Windows和linux中文件互相拷贝
  17. python中文转拼音实例_Python 将中文转拼音
  18. 在线抓包工具Whistle
  19. 法律工作者在用的小众但功能强悍的效率工具有这些
  20. 【官网文档】机器学习术语表

热门文章

  1. 《炬丰科技-半导体工艺》 光刻胶的化学性质
  2. 【行业案例分享】图吧MPS混合定位
  3. html代码右上角标签,html实现上角标的效果
  4. js整形int和byte数组互相转换
  5. 适合房产中介使用的房产管理系统源码哪个比较好用?
  6. HTML及简单标签介绍
  7. linux免采集卡直播ps4,转播篇_XBOXONE/PS4免采集卡直播教程 - 跑跑车主机频道
  8. 暴雪和网易分手百万玩家何去何从
  9. 【游戏客户端】浅谈装备系统
  10. MySQL存储过程批量插入数据