1. 程式人生 > 實用技巧 >loj10014數列分段二

loj10014數列分段二

10014.「一本通 1.2 練習 1」數列分段 II

題目描述

對於給定的一個長度為 n 的正整數數列 A ,現要將其分成 m 段,並要求每段連續,且每段和的最大值最小。

例如,將數列 4,2,4,5,1 要分成 3 段:

若分為 [4,2][4,5][1] ,各段的和分別為 6,9,1 ,和的最大值為9 ;

若分為 [4][2,4][5,1] ,各段的和分別為 4,6,6 ,和的最大值為 6;

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

所以可以得到要將數列 4 2 4 5 1 要分成 3 段,每段和的最大值最小為 6 。

輸入格式

第行包含兩個正整數 n,m;

第行包含 n 個空格隔開的非負整數 A_i,含義如題目所述。

輸出格式

僅包含一個正整數,即每段和最大值最小為多少。

樣例 輸入複製
5 3
4 2 4 5 1
輸出複製
6
資料範圍與提示

對於100% 的資料,有n<=1e5,m<=n,A_i 之和不超過 1e9 。

________________________________ 二分答案 ________________________________
 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 typedef long long ll;
 4 const  int
maxn=1e5+10; 5 ll sz[maxn]; 6 ll n,m; 7 ll l,r,ans; 8 bool pd(ll x) 9 { 10 ll sm=0,js=1; 11 for(int i=1;i<=n;++i) 12 { 13 if(sm+sz[i]>x) 14 { 15 js++; 16 sm=0; 17 } 18 sm+=sz[i]; 19 } 20 return js<=m; 21 } 22 int main()
23 { 24 scanf("%lld%lld",&n,&m); 25 for(int i=1;i<=n;++i) 26 { 27 scanf("%lld",sz+i); 28 r+=sz[i];l=max(l,sz[i]); 29 } 30 31 while(l<=r) 32 { 33 ll mid=(l+r)>>1; 34 if(pd(mid))ans=mid,r=mid-1; 35 else l=mid+1; 36 } 37 cout<<ans; 38 return 0; 39 }
View Code