zzuli 1919 (二分法 分数列 )

来源:互联网 发布:开个淘宝店铺卖什么好 编辑:程序博客网 时间:2024/05/17 07:34

1919: D

Time Limit: 1 Sec  Memory Limit:128 MB
Submit: 194  Solved: 46

SubmitStatusWeb Board

Description

晴天想把一个包含n个整数的序列a分成连续的若干段,且和最大的一段的值最小,但他有强迫症,分的段数不能超过m段,然后他就不会分了。。。他想问你这个分出来的和最大的一段的和最小值是多少?

Input

第一行输入一个整数t,代表有t组测试数据。
每组数据第一行为两个整数n,m分别代表序列的长度和最多可分的段数。
接下来一行包含n个整数表示序列。
0<=n<=50000 1<=m<=n,0<=ai<=10000。

Output

输出一个整数表示和最大的一段的最小值。

Sample Input

13 21 3 5

Sample Output

5

HINT

1 3 5 分成一段可以为1 3 5和为9,分成两段可以为1,3 5或者1 3,5,和最大的一段值分别为8,5,所以答案为5

Source

题意: 都能看明白吧? 毕竟是中文题目嘛...

分析: 当分的块数m大于n时 自然最大段的最小值就是该数列的最大值;当m小于n时,就利用二分的思想对大于最大值的部分二分趋近;

#include<iostream> #include<stdio.h> #include<string.h> #include<math.h> #include<algorithm> #include<stdlib.h> #include<queue> typedef long long ll; using namespace std;   const int MAX=50010; int a[MAX]; int n,m;   int Judge(int x) {     int s=0,cnt=0;     for(int i=0; i<n; i++)     {         if(x<a[i])             return 0;         if(s+a[i]<=x)             s+=a[i];         else        {             s=a[i];             cnt++;             if(cnt>m-1)                 return 0;         }     }     return 1; }   int Solve(int lo,int hi) {     int mid;     while(lo<hi)     {         mid=lo+(hi-lo)/2;         if(Judge(mid))             hi=mid;         else            lo=mid+1;     }     return lo; }   int main() {     int max,sum,T;     scanf("%d",&T);     while(T--)     {         scanf("%d%d",&n,&m);         if(m>n)             m=n;         max=0;         sum=0;         for(int i=0; i<n; i++)         {            scanf("%d",&a[i]);             if(max<a[i])                 max=a[i];             sum+=a[i];         }         printf("%d\n",Solve(max,sum));     }     return 0; } 


0 0
原创粉丝点击