Time Limit: 2000MS | Memory Limit: 65536K | |
Total Submissions: 29665 | Accepted: 11263 |
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 next N (1 ≤ N ≤ 100,000) days.
FJ wants to create a budget for a sequential set of exactly M (1 ≤ M ≤ N) 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
Lines 2.. N+1: Line i+1 contains the number of dollars Farmer John spends on the ith day
Output
Sample Input
7 5 100 400 300 100 500 101 400
Sample Output
500
题意:n组数据分为连贯的5组,求其中最大值的最小值。
分析:
二分money找到一个值d,然后判断C(d);
C(d):在money为d的限制条件下,判断是否能够成功分组;
程序要考虑到三种极限情况:
1.[a,b] a行b不行,使用while(ub-lb)时可能会WA
2.[a,b] a不行b行,使用while(ub>lb)时可能会超时
3.[a,b,c] 其中a不行b行,使用ub = mid-1+ub>lb时可能会得出错误答案
考虑到以上三种情况并不容易,我前几次ac的代码在考虑3中都找出了反例.比如第3种极限情况:
4 3
1 2 2 3
很多网友的ac代码,包括我自己之前的ac代码都过不了这类数据。
方法一:1到m遍历,看能否m次恰好把n个值分完。
#include <cstdio> #include <cstdlib> #include <iostream> #include <stack> #include <queue> #include <algorithm> #include <cstring> #include <string> #include <cmath> #include <vector> #include <bitset> #include <list> #include <sstream> #include <set> #include <functional> using namespace std; #define INF 0x3f3f3f3f #define MAX 100 typedef long long ll; int n,m; int x[100005]; bool C(int d) { int id = 0; for (int i = 0; i < m; i += 1){ int sum = 0; while (sum+x[id]<d && id<n){ sum += x[id]; id++; } } if(id<n) return true;//没走完,分组大于m组,mid太小 return false; } int main() { #ifndef ONLINE_JUDGE freopen("in.txt", "r", stdin); freopen("out.txt", "w", stdout); #endif cin >> n >> m; int lb = 0,ub = 0; for (int i = 0; i < n; i += 1){ cin >> x[i]; lb = max(lb,x[i]); ub = ub+x[i]; } while (ub-lb>1){ int mid = (ub+lb)/2; if(C(mid)) lb = mid;//mid太小,右移 else ub = mid; } printf("%d\n",lb); return 0; }
方法二:1到n进行分组,看n个值是否能分为m组。
#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <stack>
#include <queue>
#include <algorithm>
#include <cstring>
#include <string>
#include <cmath>
#include <vector>
#include <bitset>
#include <list>
#include <sstream>
#include <set>
#include <functional>
using namespace std;
#define INF 0x3f3f3f3f
#define MAX 100
typedef long long ll;
int n,m;
int x[100005];
bool C(int d)
{
int sum = 0,ans = 1;
for (int i = 0; i < n; i += 1){
sum += x[i];
if(sum > d){
ans++;//ans只加了m-1次,最后一次不会满足这个条件
sum = 0;
i--;
}
}
if(ans > m) return true;//>m说明mid太小
return false;
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("in.txt", "r", stdin);
freopen("out.txt", "w", stdout);
#endif
cin >> n >> m;
int lb = 0,ub = 0;
for (int i = 0; i < n; i += 1){
cin >> x[i];
lb = max(lb,x[i]);
ub = ub+x[i];
}
while (ub>lb){
int mid = (ub+lb)/2;
if(mid == lb && C(mid)) {
printf("%d\n",ub);return 0;
}
if(C(mid)) lb = mid;
else ub = mid;
}
printf("%d\n",lb);
return 0;
}
ps:给出一个poj能ac但是有误的代码:
#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <stack>
#include <queue>
#include <algorithm>
#include <cstring>
#include <string>
#include <cmath>
#include <vector>
#include <bitset>
#include <list>
#include <sstream>
#include <set>
#include <functional>
using namespace std;
#define INF 0x3f3f3f3f
#define MAX 100
typedef long long ll;
int n,m;
int x[100005];
bool C(int d)
{
int sum = 0,ans = 1;
for (int i = 0; i < n; i += 1){
sum += x[i];
if(sum > d){
ans++;
sum = x[i];
}
}
if(ans > m) return true;
return false;
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("in.txt", "r", stdin);
freopen("out.txt", "w", stdout);
#endif
cin >> n >> m;
int lb = 0,ub = 0;
for (int i = 0; i < n; i += 1){
cin >> x[i];
lb = max(lb,x[i]);
ub = ub+x[i];
}
while (ub>lb){
int mid = (ub+lb)/2;
if(C(mid)) lb = mid+1;
else ub = mid-1;
}
printf("%d\n",ub);
return 0;
}