對於給定的乙個長度為n的正整數數列a[i],現要將其分成m(m≤n)段,並要求每段連續,且每段和的最大值最小。
關於最大值最小:
例如一數列4 2 4 5 1要分成3段
將其如下分段:
[4 2][4 5][1]
第一段和為6,第2段和為9,第3段和為1,和最大值為9。
將其如下分段:
[4][2 4][5 1]
第一段和為4,第2段和為6,第3段和為6,和最大值為6。
並且無論如何分段,最大值不會小於6。
所以可以得到要將數列4 2 4 5 1要分成3段,每段和的最大值最小為6。
第1行包含兩個正整數n,m,第2行包含n個空格隔開的非負整數a[i],含義如題目所述。
僅包含乙個正整數,即每段和最大值最小為多少。
5 34 2 4 5 1
題解:最小的部分和最大值一定是存在的(以下稱其為「這個值」),只是我們還不知道。我們可以採用二分的方法逼近這個值,因為我們可以很容易地判斷乙個數是小於這個值還是大於這個值。
如果乙個數比這個值小,那麼無論如何怎麼分,也不可能把數列分成m段,使得部分和的最大值小於等於該數。因為這個值本身就是將數列分成m段其中部分和的最小值。也就是說,不能成功劃分數列的的數是比這個值小的。
如果乙個數比這個值大,那麼它就可以將數列分成m段,使得部分和的最大值小於等於該數。反過來說,能成功劃分數列的數是大於這個值的數
#include#includeusing namespace std;
int a[100010],sum[100010];
int n,m;
bool check(int max_sum)//是否存在一種劃分方法,使得部分和的最大值小於等於max_sum
}sum_section++;//無論加上最後乙個元素超出max_sum還是不超出,都要將段數+1
if(sum_section <= m)//如果段數小於等於m
return true;//可以,仔細想想這個邏輯
else//否則不可以
return false;
}int main()
int l = max_a,r = sum[n];//二分邊界,當分成n段時,顯然部分和的最大值就是max_a,當分成的段數小於n時,部分和的最大值開始增大,當分成1段時,部分和的最大值達到最大,即為數列的前n項和。如此分析,便得出了二分的邊界
while(l < r)//二分模板
cout << r << endl;//輸出r
return 0;
}
---------------------
原文:
數列分段 Section II
對於給定的乙個長度為n的正整數數列 a i 現要將其分成 m m n 段,並要求每段連續,且每段和的最大值最小。關於最大值最小 例如一數列 4 2 4 5 1 要分成 3 段 將其如下分段 42 45 1 第一段和為 6 第 2 段和為 9 第 3 段和為 1 和最大值為 9 將其如下分段 4 24...
數列分段 Section II
點我點我點我點我點我點我點我點我點我點我點我點我點我點我點我點我 二分答案 貪心 首先,分析題目,求最大值的最小化,直接聯想到二分,so我們直接二分答案,關鍵是要怎麼去高效的check,因為大家很容想到字首和,但實際上這個空間是可以省略的,為什麼呢?我們考慮乙個貪心的思路,能加的就加上,不能則新開一...
數列分段 Section II
對於給定的乙個長度為n的正整數數列 a a1 n,現要將其分成 mm m leq nm n 段,並要求每段連續,且每段和的最大值最小。關於最大值最小 例如一數列 4 2 4 5 14 2 4 5 1 要分成 33 段。將其如下分段 4 2 4 5 1 4 2 4 5 1 第一段和為 66,第 22 ...