题目大意:
农场主John是一个做账的奇才,他意识到自己快把所有钱都要花销在经营农场上了。幸好他已经将未来N天(1 ≤ N ≤ 100,000)的每天的开销都做了计算,每天花的钱的范围为[1, 10,000]。他做了一个预算,将未来N天分为M个阶段(1 ≤ M ≤ N),每个阶段包含连续的若干天,每一天都包含在某一阶段中。
现只有一个测例,测例中给出N和M,以及N天中每一天的开销,先求出如果分为M个阶段则最大的阶段开销为多少。
注释代码:
/*
* Problem ID : POJ 3273 Monthly Expense
* Author : Lirx.t.Una
* Language : C++
* Run Time : 63 ms
* Run Memory : 556 KB
*/
#include <stdio.h>
#define TRUE 1
#define FALSE 0
//maximum number of days
//预算的最大天数(数组下标取到100,000)
#define MAXDAYN 100001
typedef int BOOL;
int ep[MAXDAYN];//expense of each day,每天的开销
BOOL
xlim( int d, int n, int m ) {
//d为假设的每个阶段的开支上限
//n为天数
//m为指定的阶段数
//count为d上限条件下最少的阶段数,sum记录当前阶段的开支
int cnt, sum;
int i;//计数变量
for ( cnt = 1, sum = 0, i = 1; i <= n; i++ ) {
sum += ep[i];
if ( sum > d ) {//超出上限就加一组
cnt++;
sum = ep[i];//将当前天的开支初始化下一阶段的开支
}
}
if ( cnt > m )//上限太小导致可分的阶段数太多,因此需要提高上限
return FALSE;
else//分组数不够,表示上限太高,减小
return TRUE;
}
int
main() {
int n, m;//天数和阶段数
int i;//计数变量
int max;//最大开支
int sum;//总开支
//[lft, rht]阶段开支的可能范围
//mid为区间中点
//用mid来逼近最终的答案
int lft, rht, mid;
scanf("%d%d", &n, &m);
for ( sum = 0, max = 0, i = 1; i <= n; i++ ) {
scanf("%d", ep + i);
sum += ep[i];
if ( ep[i] > max )
max = ep[i];
}
if ( 1 == m ) {//如果只分一个阶段则结果就是总开支
printf("%d\n", sum);
return 0;
}
if ( n == m ) {//如果阶段数等于天数则结果就是最大开支
printf("%d\n", max);
return 0;
}
//以上可以避免特殊情况下的二分搜索,以降低运行时间
//区间初始化
lft = max;//由于max一定包含在某阶段中,因此阶段最低预算一定大于等于max
rht = sum;//极端情况(只有一个阶段的情况)
while ( lft <= rht ) {
mid = ( lft + rht ) >> 1;
if ( !xlim( mid, n, m ) )
lft = mid + 1;
else
rht = mid - 1;
}
printf("%d\n", mid);
return 0;
}
无注释代码:
#include <stdio.h>
#define TRUE 1
#define FALSE 0
#define MAXDAYN 100001
typedef int BOOL;
int ep[MAXDAYN];
BOOL
xlim( int d, int n, int m ) {
int cnt, sum;
int i;
for ( cnt = 1, sum = 0, i = 1; i <= n; i++ ) {
sum += ep[i];
if ( sum > d ) {
cnt++;
sum = ep[i];
}
}
if ( cnt > m )
return FALSE;
else
return TRUE;
}
int
main() {
int n, m;
int i;
int max;
int sum;
int lft, rht, mid;
scanf("%d%d", &n, &m);
for ( sum = 0, max = 0, i = 1; i <= n; i++ ) {
scanf("%d", ep + i);
sum += ep[i];
if ( ep[i] > max )
max = ep[i];
}
if ( 1 == m ) {
printf("%d\n", sum);
return 0;
}
if ( n == m ) {
printf("%d\n", max);
return 0;
}
lft = max;
rht = sum;
while ( lft <= rht ) {
mid = ( lft + rht ) >> 1;
if ( !xlim( mid, n, m ) )
lft = mid + 1;
else
rht = mid - 1;
}
printf("%d\n", mid);
return 0;
}
单词解释:
expense:n, 开支
astounding:adj, 令人震惊的
wizard:n, 术士,奇才,男巫
accounting:n, 会计,账单
run out of:vt, 用完
budget:n, 预算
sequential:adj, 连续的,相继的
fiscal:adj, 会计的,财政、国库的
schedule:vt, 计划,安排