P1182 数列分段`Section II` (二分答案+贪心)

对于给定的一个长度为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
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;
}

 

你可能感兴趣的:(贪心,二分)