列表

详情


NC50235. 数列分段 II

描述

对于给定的一个长度为N的正整数数列A,现要将其分成M段,并要求每段连续,且每段和的最大值最小。
例如,将数列要分成3段:
若分为[42][45][1],各段的和分别为6,9,1,和的最大值为9;
若分为[4][24][51],各段的和分别为4,6,6,和的最大值为6;
并且无论如何分段,最大值不会小于6。
所以可以得到要将数列要分成3段,每段和的最大值最小为6。

输入描述

第1行包含两个正整数N,M;
第2行包含N个空格隔开的非负整数A_i,含义如题目所述。

输出描述

仅包含一个正整数,即每段和最大值最小为多少。

示例1

输入:

5 3
4 2 4 5 1

输出:

6

原站题解

上次编辑到这里,代码来自缓存 点击恢复默认模板

C++14(g++5.4) 解法, 执行用时: 65ms, 内存消耗: 1304K, 提交时间: 2019-10-23 15:46:15

#include<bits/stdc++.h>
using namespace std;

int main() {
  int N, M; cin >> N >> M;
  vector<int> A(N); for (auto &a: A) cin >> a;
  int lo = *max_element(A.begin(), A.end());
  int hi = accumulate(A.begin(), A.end(), 0ll) + 1;
  while (lo < hi) {
    int mid = (lo + hi) / 2;
    int cnt = 1;
    int cur = 0;
    for (auto a: A) {
      if (cur + a > mid) cnt++, cur = 0;
      cur += a;
    }
    if (cnt > M) lo = mid + 1;
    else hi = mid;
  }
  cout << hi << endl;
}

C++(clang++ 11.0.1) 解法, 执行用时: 22ms, 内存消耗: 792K, 提交时间: 2022-09-06 11:46:50

#include<cstdio>
const int M=1e5+10;
int a[M],n,m;
bool check(int mid)
{
	int t=1,d=0;
	for(int i=1;i<=n;i++)
	{
		if(a[i]>mid)return 0;
		if(d+a[i]<=mid)d+=a[i];
		else t++,d=a[i];
	}
	return t<=m;
}
int main()
{
	scanf("%d %d",&n,&m);
	for(int i=1;i<=n;i++)scanf("%d",&a[i]);
	int l=1,r=1e9,ans=0;
	while(l<=r)
	{
		int mid=l+r>>1;
		if(check(mid))r=mid-1,ans=mid;
		else l=mid+1; 
	}
	printf("%d",ans);
	return 0;
}

上一题