数列分段`Section II`

题目

点我点我点我点我点我点我点我点我点我点我点我点我点我点我点我点我

题解

本题解法:

二分答案+贪心

思路:

首先,分析题目,求最大值的最小化,直接联想到二分,So我们直接二分答案,关键是要怎么去高效的check,因为大家很容想到前缀和,但实际上这个空间是可以省略的,为什么呢?我们考虑一个贪心的思路,能加的就加上,不能则新开一段,so对于二分的值x,我们从数列a从前往后扫,如果tot大于了x,我们不加而是tot重新赋值并且num++,最后只需判断num是否不小于m就行了。这样判断与前缀和一样是O(n)的复杂度,但是节省了空间。虽然实际上毫无卵用

code

#include <bits/stdc++.h>
#define MAXX 101000
#define ll long long
using namespace std;

inline int read() {
	int s = 0, w = 1;
	char ch = getchar();
	while(!isdigit(ch)) { if(ch == '-') w = -1; ch = getchar(); }
	while(isdigit(ch)) { s = (s << 1) + (s << 3) + (ch ^ 48); ch = getchar(); }
	return s * w;
}

int n, m;
int righ, lef, mid, cnt = 0, tot = 0;
int a[MAXX];

inline bool check(int x) {
	for (int i = 1; i <= n; ++i) {
		if (tot + a[i] <= x) tot += a[i];
		else {
			tot = a[i];
			cnt++;
		}
	}
	return cnt >= m;
}

int main() {
	n = read(); m = read();
	for (int i = 1; i <= n; ++i) {
		a[i] = read();
		righ += a[i];
		lef = max(lef, a[i]);
	}
	while (lef <= righ) {
		mid = (lef + righ) >> 1;
		tot = 0, cnt = 0;
		if (check(mid)) lef = mid + 1;
		else righ = mid - 1; 
	}
	printf("%d\n", lef);
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值