1. 程式人生 > >數列分段`Section II`

數列分段`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;
}