Codeforces-1667: B Optimal Partition
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=maxj{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(nlogn)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相关推荐
- CF 1667B Optimal Partition
https://codeforces.com/problemset/problem/1667/B
- 【CodeForces - 1038B 】Non-Coprime Partition (构造,数组特征)
题干: Find out if it is possible to partition the first nn positive integers into two non-empty disjoi ...
- Educational Codeforces Round 39 A Partition
传送门 分治就好了,哈哈大于小于0的数据分开算 #include <bits/stdc++.h> using namespace std; typedef long long ll ; t ...
- 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 ...
- Boring Partition(CF-239D)
Problem Description This problem is the most boring one you've ever seen. Given a sequence of intege ...
- Codeforces Round #783 (Div. 2) A-F
A.Direction Change 讨论一下每种移动的情况即可.先交替,然后再走多的. 走多的过程需要交替在其他方向移动. #include <iostream> #include &l ...
- Codeforces Round 783 补题
目录 官网链接 div2 C Make it Increasing div1 B Optimal Partition C Half Queen Cover D Edge Elimination E C ...
- codeforces每日5题(均1500)-第二十一天
Walking Robot 题面翻译 Description 在一个数轴上,有一个机器人要从 x=0x = 0x=0 处移动到 x=nx = nx=n 处.机器人身上有两种电池,第一种是普通电池,第二 ...
- codeforces 1500分题部分题解(1249c2 770a 1264a 1253c 114b)
C2. Good Numbers (hard version) 注意 3x 意思是 3^x time limit per test2 seconds memory limit per test256 ...
最新文章
- 从零开始一起学习SLAM | SLAM有什么用?
- 基本概念_程序员基本功——链表的基本概念
- 火狐渗透测试浏览器_微软、火狐浏览器、Opera浏览器等主流平台纷纷布局IPFS:大势所趋...
- read write spinlock
- cocos2d-x游戏实例(24)-简易动作游戏(2)
- 【模板】可持久化并查集
- Visual Studio 2010旗舰版在安装Windows Phone 7 SDK后项目模版里没有Windows Phone 项目解决办法...
- vba 指定列后插入列_Excle中的VBA介绍分享
- 批处理延迟sleep应用
- 潭州课堂25班:Ph201805201 并发(非阻塞,epoll) 第十课 (课堂笔记)
- 计算机偏门术语,没听说过 WinXP偏门应用技巧四则
- java jbpm工作流_JBPM工作流
- android 获取软件签名,获取Android应用签名
- 重庆“易法院”上线 民众足不出户参与诉讼全过程
- linux下的串口编程
- 使用pscp命令将Windows和linux中文件互相拷贝
- python中文转拼音实例_Python 将中文转拼音
- 在线抓包工具Whistle
- 法律工作者在用的小众但功能强悍的效率工具有这些
- 【官网文档】机器学习术语表