数列分段---二分+贪心

数列分段---二分+贪心

题目描述

对于给定的一个长度为N的正整数数列A-iA−i,现要将其分成M(M≤N)段,并要求每段连续,且每段和的最大值最小。

关于最大值最小:

例如一数列4 2 4 5 1要分成3段

将其如下分段:

[4 2][4 5][1]

第一段和为6,第2段和为9,第3段和为1,和最大值为9。

将其如下分段:

[4][2 4][5 1]

第一段和为4,第2段和为6,第3段和为6,和最大值为6。

并且无论如何分段,最大值不会小于6。

所以可以得到要将数列4 2 4 5 1要分成3段,每段和的最大值最小为6。

输入输出格式

输入格式:

第1行包含两个正整数N,M。

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

输出格式:

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

输入输出样例

输入样例#1: 复制

5 3

4 2 4 5 1

输出样例#1: 复制

6

#include

#include

using namespace std;

int arr[100002];

int n, m;

int lef, rig, mid;

int tu, ts;

bool judge(int mid)//用来判别是否每一段都可以小于mid

{

for (int i = 1; i <= n; i++)

{

if (tu + arr[i]<= mid)//如果还是小于mid,就继续加上去

tu += arr[i];

else//否则就开启另一段,ts加一,并且设置tu为当前的数字

{

ts += 1;

tu = arr[i];

}

}

return ts >= m;

}

int main()

{

cin >> n >> m;

for (int i = 1; i <= n; i++)

{

cin >> arr[i];

rig += arr[i];

lef = lef > arr[i] ? lef : arr[i];

}

while (lef<=rig)

{

mid = (lef + rig) / 2;

ts = tu = 0;

if (judge(mid))//如果最后的ts是大于m的话,说明mid太小了,需要lef往右移

lef = mid + 1;

else//否则就是mid太大了

rig = mid - 1;

}

cout << lef << endl;

system("pause");

return 0;

}

解析:

最大值的最小值:二分的标志

我们的二分是从这个数列中的最大值到数列总和,为什么?

从最大值开始是因为这个序列最少一段的数量是一个数字,还要这一段数字最大,所以要从最大的数开始。到总和结束是因为小于总和的值都有可能是最后的答案,需要二分来判别

具体见注释

相关推荐

为什么计算机里没有桌面显示不出来,电脑开机后桌面显示不出来如何修复_电脑开机后桌面没有东西的处理办法-系统城...
SENSORO怎么样
365bet365官网

SENSORO怎么样

📅 09-25 👁️ 6934
Beijing 细颗粒物 (PM2.5) 水平:实时空气污染警报
365bet365官网

Beijing 细颗粒物 (PM2.5) 水平:实时空气污染警报

📅 09-07 👁️ 4024