题意:给你一个序列,你可以选择序列的一个前缀,把前缀分成k个连续的部分,要求这k个部分的区间和的最大值尽量的小,问这个最小的最大值是多少?

思路:首先看到最大值的最小值,容易想到二分。对于每个二分值mid,我们判断原序列是否可以构成k个区间和小于等于mid的区间,这个可以用DP来做。我们先求出序列的前缀和,这样可以把区间和变成前缀相减的形式。之后,对于当前的前缀和sum[i], 我们找前缀和大于等于sum[i] - mid的状态中dp值最大的向自己转移。如果最后存在状态的dp值大于等于k,那么说明二分的mid值偏大,要缩小上边界。反之亦然。dp用离散化 + 线段树优化,总复杂度O(n * logn) * log(值域)

代码:

#include <bits/stdc++.h>
#define LL long long
#define ls (o << 1)
#define rs (o << 1 | 1)
using namespace std;
const int maxn = 200010;
LL sum[maxn];
LL a[maxn];
LL b[maxn];
int dp[maxn], mx[maxn * 4];
int n, m, tot;
void build(int o, int l, int r) {
if(l == r) {
mx[o] = -1;
return;
}
int mid = (l + r) >> 1;
build(ls, l, mid);
build(rs, mid + 1, r);
mx[o] = max(mx[ls], mx[rs]);
}
void update(int o, int l, int r, int p, int val) {
if(l == r) {
mx[o] = max(mx[o], val);
return;
}
int mid = (l + r) >> 1;
if(p <= mid) update(ls, l, mid, p, val);
else update(rs, mid + 1, r, p, val);
mx[o] = max(mx[ls], mx[rs]);
}
int query(int o, int l, int r, int ql, int qr) {
if(ql > qr) return -1;
if(l >= ql && r <= qr) {
return mx[o];
}
int mid = (l + r) >> 1, ans = -1;
if(ql <= mid) ans = max(ans, query(ls, l, mid, ql, qr));
if(qr > mid) ans = max(ans, query(rs, mid + 1, r, ql, qr));
return ans;
}
bool solve(LL mid) {
build(1, 1, tot);
update(1, 1, tot, lower_bound(b + 1, b + 1 + tot, 0) - b, 0);
for (int i = 1; i <= n; i++) {
int p = lower_bound(b + 1, b + 1 + tot, sum[i] - mid) - b;
int p1 = lower_bound(b + 1, b + 1 + tot, sum[i]) - b;
int tmp = query(1, 1, tot, p, tot);
if(tmp == -1) dp[i] = -1;
else dp[i] = tmp + 1;
if(dp[i] >= m) return 0;
update(1, 1, tot, p1, dp[i]);
}
return 1;
}
int main() {
int T;
// freopen("input.txt", "r", stdin);
// freopen("1.in", "r", stdin);
scanf("%d", &T);
while(T--) {
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; i++) {
scanf("%lld", &a[i]);
sum[i] = sum[i - 1] + a[i];
b[i] = sum[i];
}
b[n + 1] = 0;
sort(b + 1, b + 1 + n + 1);
tot = unique(b + 1, b + 1 + n + 1) - (b + 1);
LL l = -2e14, r = 2e14;
while(l < r) {
LL mid = (l + r) >> 1;
if(solve(mid)) l = mid + 1;
else r = mid;
}
printf("%lld\n", l);
}
}

  

2019HDU多校第三场 Distribution of books 二分 + DP的更多相关文章

  1. 2019HDU多校第三场F Fansblog——威尔逊定理&&素数密度

    题意 给定一个整数 $P$($10^9 \leq p\leq 1^{14}$),设其前一个质数为 $Q$,求 $Q!  \ \% P$. 分析 暴力...说不定好的板子能过. 根据威尔逊定理,如果 $ ...

  2. 2019HDU多校第三场 K subsequence——最小费用最大流

    题意 给定一个 $n$ 个整数的数列,从中至多选取 $k$ 个上升子序列(一个元素最多被选一次),使得选取的元素和最大. 分析 考虑这个问题和经典网络流问题“最长不下降子序列”相似,我们考虑对这个建图 ...

  3. [2019HDU多校第三场][HDU 6603][A. Azshara's deep sea]

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6603 题目大意:给出一个凸包,凸包内有若干个圆,要求画尽可能多的对角线使得他们两两不在凸包内相交且不与 ...

  4. 2019Hdu多校第三场:1007 Find the answer(multiset 解法)

    原题链接: Find the answer c++中,multiset是库中一个非常有用的类型,它可以看成一个序列,插入一个数,删除一个数都能够在O(logn)的时间内完成,而且他能时刻保证序列中的数 ...

  5. 2018杭电多校第三场1003(状态压缩DP)

    #include<bits/stdc++.h>using namespace std;const int mod =1e9+7;int dp[1<<10];int cnt[1& ...

  6. 2018 HDU多校第三场赛后补题

    2018 HDU多校第三场赛后补题 从易到难来写吧,其中题意有些直接摘了Claris的,数据范围是就不标了. 如果需要可以去hdu题库里找.题号是6319 - 6331. L. Visual Cube ...

  7. 牛客多校第三场 F Planting Trees

    牛客多校第三场 F Planting Trees 题意: 求矩阵内最大值减最小值大于k的最大子矩阵的面积 题解: 矩阵压缩的技巧 因为对于我们有用的信息只有这个矩阵内的最大值和最小值 所以我们可以将一 ...

  8. 牛客多校第三场 G Removing Stones(分治+线段树)

    牛客多校第三场 G Removing Stones(分治+线段树) 题意: 给你n个数,问你有多少个长度不小于2的连续子序列,使得其中最大元素不大于所有元素和的一半 题解: 分治+线段树 线段树维护最 ...

  9. 2019杭电多校第三场hdu6606 Distribution of books(二分答案+dp+权值线段树)

    Distribution of books 题目传送门 解题思路 求最大值的最小值,可以想到用二分答案. 对于二分出的每个mid,要找到是否存在前缀可以份为小于等于mid的k份.先求出这n个数的前缀和 ...

随机推荐

  1. elasticsearch相关聚合查询示例

    索引(index):logstash-nginx-*,type:nginx_access 请求路径: 1.按照某个字段进行分组统计访问量 { "query": { "bo ...

  2. jsp中引入js文件缓存问题解决

    加上版本UUID <script charset="utf-8" src="${basePath}js/souke/soukegalist.js?v=<%=U ...

  3. 全球的IPv6部署急剧增加,但中国几乎没有一个地方部署?

    全球的IPv6部署继续增加,但中国在IPv6方面还需要努力,从部署图上分析,中国几乎没有几个地方是普及IPv6的.这6年来,自世界IPv6发布以来,全球网络和服务提供商的IPv6部署水平急剧增加.如图 ...

  4. pythonerror ValueError:invalid literal for int() with base 10: '3.14'

    解释:对于int()来说,文本输入‘3.14’这个输入是无效的,原因是int类要求输入数字或者整数字符 解决:a= int(float(value)) 注:int本身是一个类,所以返回的是int类,i ...

  5. 【leetcode】636. Exclusive Time of Functions

    题目如下: 解题思路:本题和括号匹配问题有点像,用栈比较适合.一个元素入栈前,如果自己的状态是“start”,则直接入栈:如果是end则判断和栈顶的元素是否id相同并且状态是“start”,如果满足这 ...

  6. 第一周作业—N42-虚怀若谷

    一.Linux发行版描述. Linux发行版主要有三个分支:Slackware.Debian.Redhat: (1) Slackware: SUSE:基于Slackware二次开发的一款Linux,主 ...

  7. mock.js模拟生成假数据

    mock使用方法很简单, 下面是简单的用法, 详细的用法可以看官方文档, 写的很清楚, 下面的代码直接拷贝到本地html文件, 双击打开即可生成你想要的数据 <!DOCTYPE html> ...

  8. tomcat正常启动输入localhost:8080显示404错误

    找了半天才解决. 看这个贴子: https://www.cnblogs.com/lovelanglangyou/p/7410937.html 简而言之: 需要修改eclipse中的server配置,e ...

  9. xunit的assert常用部分方法解释

    布尔:True(返回bool的方法或者字段) 判断是否为trueFalse(返回bool的方法或者字段) 判断是否为false 字符串(区分大小写):Equal(期待结果,实际结果) 判断输出值和期待 ...

  10. C语言|博客作业12

    一.我学到的内容(整理本课程所学,[用思维导图的方式] 二.我的收获(包括我完成的所有作业的链接+收获)不能只有作业链接,没有收获 作业链接 收获 https://edu.cnblogs.com/ca ...