【题目描述】:
农民约翰是一个惊人的会计,他意识到可能没有钱来经营农场。他已经准确计算出接下来的N 天,每天所要花费的钱ai。
约翰想将这N 天,划分成M 段,每段至少1天,第i段的和为sum[i]。
请你求出如何划分使得max{sum[i]}最小,其值是多少?
【输入描述】:
第一行两个整数N和M。
第二行N个整数,顺序表示每一天的花费。
【输出描述】:
输出划分M 段后,最大段的最小值。
【样例输入】:
7 5
200 300 300 200 500 221 420
【样例输出】:
500
【时间限制、数据范围及描述】:
时间:1s 空间:128M
1<=ai<=10,000; 1<=N<=100,000
详解看代码:
#include<stdio.h>
#include<iostream>
using namespace std;
const int N = 100005;
int n, m, l = 0, r = 0, mid = 0;
int a[N];
int read()
{
int f = 1, ans = 0;
char c;
c = getchar();
while(c < '0' || c > '9')
{
if(c == '-')
{
f = -1;
}
c = getchar();
}
while('0' <= c && c <= '9')
{
ans = ans * 10 + c - '0';
c = getchar();
}
return ans * f;
}
bool IF(int mi)
{
int sum = 0, t = 0;
for(int i = 1; i <= n; i++)
{
if(sum + a[i] > mi)如果前几个月加上这个月的钱大于这次尝试的月开销,那么说明这个月的钱应该放在下个月里
{
sum = a[i];
++t;
}
else
sum += a[i];
}
if(t >= m)
return true;
else
return false;
}
//如果按照mid的分割方法,最大分割出t个月大于m,则可以继续增加开销,
// 注意,这里是说,最少分出的月份是t,那么t>=m,则可以继续增加开销,以便使t变小 //本段注释为引用他人的话
//详见https://blog.youkuaiyun.com/abc15766228491/article/details/78827946
int main()
{
freopen("51.in", "r", stdin);
freopen("51.out", "w", stdout);
n=read();
m=read();
for(int i = 1; i <= n; i++)
{
a[i]=read();
l = max(a[i], l);
r = r + a[i];
}
while(l <= r)
{
mid = (l + r) / 2;
if(IF(mid))
l = mid + 1;
else
r = mid - 1;
mid = (l + r) / 2;
}
printf("%d", l);//一定是l而不是mid,因为l需要被最后一次修改才是正解,此时mid与l不是一个数,我调试了好久......
return 0;
}
至于为什么做这题,,一方面是为了学习二分,,,,另一方面,,为了明天考试(要不然我才不那么勤奋呢^_^)................老天保佑我吧!!!嗷嗷!!
天下无双!(个人中二病)