1243:月度開銷
時間限制: 1000 ms 內存限制: 65536 KB
提交數: 5287 通過數: 1850
【題目描述】
農夫約翰是一個精明的會計師。他意識到自己可能沒有足夠的錢來維持農場的運轉了。他計算出並記錄下了接下來 N (1 ≤ N ≤ 100,000) 天裏每天需要的開銷。
約翰打算爲連續的M (1 ≤ M ≤ N) 個財政週期創建預算案,他把一個財政週期命名爲fajo月。每個fajo月包含一天或連續的多天,每天被恰好包含在一個fajo月裏。
約翰的目標是合理安排每個fajo月包含的天數,使得開銷最多的fajo月的開銷儘可能少。
【輸入】
第一行包含兩個整數N,M,用單個空格隔開。
接下來N行,每行包含一個1到10000之間的整數,按順序給出接下來N天裏每天的開銷。
【輸出】
一個整數,即最大月度開銷的最小值。
【輸入樣例】
7 5
100
400
300
100
500
101
400
【輸出樣例】
500
【提示】
若約翰將前兩天作爲一個月,第三、四兩天作爲一個月,最後三天作爲一個月,則最大月度開銷爲500。其他任何分配方案都會比這個值更大。
思路:分治用二分來做。
#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
int n,m,a[100009], maxx = 0, tot,ans;
bool check(int);
int main(){
scanf("%d%d",&n,&m);//輸入n天,m個財政週期
for(int i = 1; i <= n ;i++)
{
scanf("%d",&a[i]);
tot += a[i];//二分的右端點是總的開銷
if(a[i] > maxx ) maxx = a[i];//二分的左端點是n天中最大的開銷
}
int l = maxx, r = tot, mid;
while(l <= r)
{
mid = (l + r)>>1;
if(check(mid)){
ans = mid;//記錄答案
r = mid -1;
}
else
l = mid + 1;//否則擴大範圍
}
printf("%d" ,ans);
}
bool check(int x){//當最小值是x時是否可以
int sum = 0, month = 1;
for(int i = 1; i<=n; i++)
{
if(sum + a[i] > x)//sum是一直累加,當超過x時月份++,說明這一天自己另一個月份
{
sum = a[i];
month++;
}else
sum += a[i];
}
if(month <= m) return 1;//月份等於m時正好分成m個月份,小於m時,可以將某些月份中的天數拆開組成新月份,滿足分成m個月份
else
return 0;
}