洛谷P1182 數列分段`Section II`

題目描述

對於給定的一個長度爲N的正整數數列A-iA−i,現要將其分成M(M≤N)M(M≤N)段,並要求每段連續,且每段和的最大值最小。

關於最大值最小:

例如一數列4 2 4 5 142451要分成33段

將其如下分段:

[4 2][4 5][1][42][45][1]

第一段和爲66,第22段和爲99,第33段和爲11,和最大值爲99。

將其如下分段:

[4][2 4][5 1][4][24][51]

第一段和爲44,第22段和爲66,第33段和爲66,和最大值爲66。

並且無論如何分段,最大值不會小於66。

所以可以得到要將數列4 2 4 5 142451要分成33段,每段和的最大值最小爲66。

輸入輸出格式

輸入格式:

 

第11行包含兩個正整數N,M。

第22行包含NN個空格隔開的非負整數A_iAi​,含義如題目所述。

 

輸出格式:

 

一個正整數,即每段和最大值最小爲多少。

 

輸入輸出樣例

輸入樣例#1: 

5 3
4 2 4 5 1

輸出樣例#1: 

6

說明

對於20\%20%的數據,有N≤10N≤10;

對於40\%40%的數據,有N≤1000N≤1000;

對於100\%100%的數據,有N≤100000,M≤N, A_iN≤100000,M≤N,Ai​之和不超過10^9109。

解法:二分答案

要找到滿足每段和的最大值最小的數。

定義C(d):能找到每段和的最大值小於等於d =>等價於 每一段的和都小於等於d

我們可以貪心的來找,每次都儘量找儘量多的並且和小於d的爲一段

如果最後找到的段數小於所需要的段數,則說明存在

因爲我們可以拆分任意一段使得段數增加

如果可以r=mid 反之l=mid

最後r即爲最後的答案。

然而這樣以後還是wa了一個點。

最後發現沒有考慮到下界最小必須是最大的那個數組元素。

那麼我們直接在讀入的時候處理上下界即可(上界爲所有數的和)

PS.此外,下界設爲0也可以,只需要在判斷sum大小的時候判斷返回false。

#include <bits/stdc++.h>
using namespace std;
const int maxn = 2e5 + 10;
int loc[maxn];
int a, b;
bool C(int mid)
{
    //構造出b段 使得每段都小於等於mid
    int sum = 0, crt = 0;
    int i = 0;
    while(crt < a)
    {
        sum += loc[crt++];
        while(crt < a && sum + loc[crt] <= mid)
            sum += loc[crt++];
        i++;
        sum = 0;
    }
    return i <= b;
}
int main()
{
    //freopen("D:\\Chrome下載文件\\testdata.in", "r", stdin);
    ios::sync_with_stdio(false);
    cin.tie(0);
    cin >> a >> b;
    int l = 0, r = 0;
    for(int i = 0; i < a; i++)
    {
        cin >> loc[i];
        l = max(l, loc[i]);
        r += loc[i];
    }
    for(int i = 0; i < 100; i++)
    {
        int mid = (l + r) / 2;
        if(C(mid))
            r = mid;
        else
            l = mid;
    }
    cout << r << endl;
    return 0;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章