POJ 3273 Monthly Expense (二分枚举)

来源:互联网 发布:桌面切换软件 编辑:程序博客网 时间:2024/06/01 08:45


Monthly Expense
Time Limit: 2000MS Memory Limit: 65536KTotal Submissions: 15822 Accepted: 6321

Description

Farmer John is an astounding accounting wizard and has realized he might run out of money to run the farm. He has already calculated and recorded the exact amount of money (1 ≤moneyi ≤ 10,000) that he will need to spend each day over the nextN (1 ≤ N ≤ 100,000) days.

FJ wants to create a budget for a sequential set of exactlyM (1 ≤ MN) fiscal periods called "fajomonths". Each of these fajomonths contains a set of 1 or more consecutive days. Every day is contained in exactly one fajomonth.

FJ's goal is to arrange the fajomonths so as to minimize the expenses of the fajomonth with the highest spending and thus determine his monthly spending limit.

Input

Line 1: Two space-separated integers:N and M
Lines 2..N+1: Line i+1 contains the number of dollars Farmer John spends on theith day

Output

Line 1: The smallest possible monthly limit Farmer John can afford to live with.

Sample Input

7 5100400300100500101400

Sample Output

500

Hint

If Farmer John schedules the months so that the first two days are a month, the third and fourth are a month, and the last three are their own months, he spends at most $500 in any month. Any other method of scheduling gives a larger minimum monthly limit.

Source

USACO 2007 March Silver

题目链接:http://poj.org/problem?id=3273

题目大意:给出一个人在n天的花费,要求将其分成m组,每组的天数是连续的,要使得每组花费之和尽可能的小,求各组花费之中的最大值

题目分析:显然那个划分的值是有范围的,我们令范围的上限为所有花费之和,即划分为1组,范围的下限为所有话费中的最大值,即划分为n组,因为要求的是各组花费的最大值,然后答案就在这个范围之间了,我们通过二分枚举每一个在当前范围内的划分,模拟分组过程,因为要求每组是连续的,最后划分出来的组数如果小于m则说明划分值偏大,否则划分值偏小,若相等则继续枚举,注意这里不能退出,因为这只是一组合法解,题目要求的是使得每组花费之和尽可能的小,意思差不多相当于尽可能均分,因此要继续二分枚举直到二分结束。

#include <cstdio>#include <algorithm>using namespace std;int c[100005];int main(){    int n, m, sum = 0, ma = 0, l, r, mid;    scanf("%d %d", &n, &m);    for(int i = 0; i < n; i++)    {        scanf("%d", &c[i]);        sum += c[i];        ma = max(ma, c[i]);    }    r = sum;    l = ma;    mid = (l + r) / 2;    while(l < r)    {        int tmp = 1, now = 0;        for(int i = 0; i < n; i++)        {            if(c[i] + now <= mid)                now += c[i];            else            {                now = c[i];                tmp++;            }        }        //这里注意不能反!!因为有等于的情况,因为tmp=m时我们要尽量减小划分值        //这是题目的要求,让各组和尽可能小,反了肯定wa        if(tmp > m)            l = mid + 1;        else              r = mid - 1;        mid = (l + r) / 2;    }    printf("%d\n", mid);}


0 0
原创粉丝点击