对于给定的一个长度为N的正整数数列A−iA-iA−i,现要将其分成M(M≤N)M(M≤N)M(M≤N)段,并要求每段连续,且每段和的最大值最小。
关于最大值最小:
例如一数列424514 2 4 5 142451要分成333段
将其如下分段:
[42][45][1][4 2][4 5][1][42][45][1]
第一段和为666,第222段和为999,第333段和为111,和最大值为999。
将其如下分段:
[4][24][51][4][2 4][5 1][4][24][51]
第一段和为444,第222段和为666,第333段和为666,和最大值为666。
并且无论如何分段,最大值不会小于666。
所以可以得到要将数列424514 2 4 5 142451要分成333段,每段和的最大值最小为666。
输入输出格式
输入格式:
第111行包含两个正整数N,M。
第222行包含NNN个空格隔开的非负整数AiA_iAi,含义如题目所述。
输出格式:
一个正整数,即每段和最大值最小为多少。
输入输出样例
输入样例#1: 复制
5 3 4 2 4 5 1
输出样例#1: 复制
6
说明
对于20%20\%20%的数据,有N≤10N≤10N≤10;
对于40%40\%40%的数据,有N≤1000N≤1000N≤1000;
对于100%100\%100%的数据,有N≤100000,M≤N,AiN≤100000,M≤N, A_iN≤100000,M≤N,Ai之和不超过10910^9109。
思路:经典二分题,二分答案,很明显的答案的区间在【max,sum 】之间(max为数组中最大值,sum为数组和),
检测函数只要判断不超过mid的段数即可
#include<bits/stdc++.h>
using namespace std;
#define maxn 100005
#define inf 2*1e9
typedef long long ll;
ll n,m,arr[maxn],l,r;
bool checked(ll x)
{
ll num = 0,t = 0;
for(ll i = 0; i < n; i++)
{
if(arr[i]+t <= x)
{
t += arr[i];
}
else
{
num++;
t = arr[i];
}
}
if(num < m)
return 1;
else
return 0;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
cin >> n >> m;
for(ll i = 0; i < n; i++)
{
cin >> arr[i];
r += arr[i];
l = max(l,arr[i]);
}
while(l < r)
{
ll mid = (l+r) >> 1;
if( checked(mid) == 1 )
{
r = mid;
}
else
{
l = mid +1;
}
}
cout << l << endl;
return 0;
}