Datahub
数据改变生活

分组

发表时间:2022-10-27 20:17

分组

描述

有 n 个正整数排成一排,你要将这些数分成m 份(同一份中的数字都是连续的,不能隔开),同时数字之和最大的那一份的数字之和尽量小。

输入

输入的第一行包含两个正整数 n,m。接下来一行包含n 个正整数。

输出一个数,表示最优方案中,数字之和最大的那一份的数字之和。

样例 1 输入

样例 1 输

样例 1 解释

若分成 2 和 1、2、2、3,则最大的那一份是 1+2+2+3=8; 若分成 2、1 和 2、2、3,则最大的那一份是 2+2+3=7;

若分成 2、1、2 和 2、3,则最大的那一份是 2+1+2 或者是 2+3,都是 5; 若分成 2、1、2、2 和 3,则最大的那一份是 2+1+2+2=7。

所以最优方案是第三种,答案为 5。

样例 2

请查看下发文件内的 sample2_input.txt 和 sample2_output.txt。

限制

对于 50%的数据,n ≤ 100,给出的 n 个正整数不超过 10;

对于 100%的数据,m ≤ n ≤ 300000,给出的 n 个正整数不超过 1000000。时间:4 sec

空间:512 MB

提示

[大家记得看到“最大的最小”这一类语言,一定要想二分能不能做。]

[我们二分最大的那一份的和 d,然后从左向右分组,在一组中,在和不超过d 的情况下尽量往右分。若最终分出来的组数小于等于m,则这显然是合法的(我们在分出来的组里随便找个地方切开,总能变到m 组,且每组的和不超过 d)]

[这个 d 显然是单调的,即,若和不超过d 能分成m 组,则和不超过 d+1 也是能分成m 组的,故二分正确。]

代码

#include<iostream> #include<vector>

#pragma warning(disable:4996) using namespace std;

typedef long long ll;

bool check(ll mid, ll n, ll m,vector<int> &a)

{

ll sum = 0;

int cut = 1;

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

{

if (a[i] > mid)

return false;

sum += a[i];

if (sum > mid)

{

sum = a[i];

cut += 1;

}

}

return cut <= m;

}

ll GetAnswer(ll n, ll m, vector<int> &a)

{

ll l = 1, r = 0;

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

{

r += a[i];

}

while (l <= r)

{

ll mid = (l + r) / 2;

if (check(mid, n, m, a))

r = mid - 1;

else

l = mid + 1;

}

return r + 1;

}

int main()

{

ll n, m;

cin >> n >> m;

vector<int> a;

for (ll i = 0; i < n; ++i)

{

int temp;

scanf("%d", &temp);

a.emplace_back(temp);

}

ll result = GetAnswer(n, m, a);

cout << result << endl;

return 0;

}


上一篇大转盘
下一篇道路升级
文章分类: 数据结构例题
分享到:
QQ:258506508                                     联系电话:020-000000    000-000000                                   联系邮箱:xxx@.co.m                                     联系地址:XXX省XXX市XXX县XXX路