題目描述
對於給定的一個長度爲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;
}