【模板】【P1182】数列分段II——二分答案

题意:给定一列数,分成m段,使每段和的最大值最小。

  考虑二分最小段和size,答案显然满足单调性。可以在每次check中累加数列元素判断当前组的总和是否在size以内。由于序列元素均为非负整数,前缀和数组的值满足非严格单调递增,那么可以在前缀和上再套一个二分来优化暴力累加的过程。

  我不知道优化以后的复杂度怎么分析,反正它跑的快多了

代码:

  1. #include <iostream>  
  2. #include <cstdio>  
  3. #define maxn 100010   
  4. using namespace std;  
  5. int a[maxn], n, m;  
  6. long long s[maxn];  
  7. bool div(int sum) {  
  8.     int cnt = 0;  
  9.     for (int i = 1; i <= n; ) {  
  10.         if (a[i] > sum) return false;  
  11.         int l = i, r = n;  
  12.         while (l < r) {  
  13.             int mid = (l + r + 1) >> 1;  
  14.             s[mid] - s[i - 1] <= sum ? l = mid : r = mid - 1;  
  15.         }  
  16.         ++cnt, i = l + 1;  
  17.     }  
  18.     return cnt <= m;  
  19. }  
  20. int main() {  
  21. //  freopen("testdata-10.in", "r", stdin);  
  22.     ios::sync_with_stdio(0);  
  23.     cin >> n >> m;  
  24.     int l = 0, r = 0;  
  25.     for (int i = 1; i <= n; ++i)  
  26.         cin >> a[i], s[i] = a[i] + s[i - 1], l = max(l, a[i]);  
  27.     r = s[n];  
  28.     while (l < r) {  
  29.         long long mid = (l + r) >> 1;  
  30.         if (div(mid))  
  31.             r = mid;  
  32.         else l = mid + 1;  
  33.     }  
  34.     cout << l;  
  35.     return 0;  
  36. }  

猜你喜欢

转载自www.cnblogs.com/TY02/p/11366562.html