UVA 714 Copying Books
给你m本书,每本a[i]页(0<=i<m),把他们分成k个区间,使这k个区间和的最大值最小。。
我们可以先找到这m本书的最大页数max, 和所有书的页数和sum,则这k个区间中 每个区间的区间和一定在[mmax,sum]中,(即分为m个区间,我们要的结果就是这m个数中的最大值,如果分为一个区间,结果就是所有数的页数和)
我们可以用二分先找到这个值(最大值中最小的数),判定条件就是能否分成k份。
剩下的就是根据这个值标记分开的位置,但为了在有多种结果时,前面区间尽量小,应从后往前分开,如果要求k分,我们只用了k-1分就完成了,剩下的要在前面按顺序补上(详看代码吧)
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <algorithm> 5 #define sc(x) scanf("%d", &x) 6 #define sc1(x) scanf("%lld", &x) 7 #define sc2(x,y) scanf("%d%d", &x, &y) 8 #define pf(x) printf("%lld", x) 9 #define FOR(i,b,e) for(int i=b;i<e;i++) 10 #define CL(x,y) memset(x,y,sizeof(x)) 11 using namespace std; 12 typedef long long ll; 13 const int MAX = 505; 14 int m, k; 15 ll arr[MAX], sum, Min, ans; 16 bool used[MAX]; 17 inline int div(ll key) 18 { 19 CL(used, 0); 20 int cnt=0; 21 int pos=m-1; 22 while(pos>=0) 23 { 24 long long sum=0; 25 bool ok=true; 26 while(pos>=0 && sum+arr[pos] <= key) 27 { 28 ok=false; 29 sum += arr[pos]; 30 --pos; 31 } 32 if(ok) 33 { 34 return k+1; // 返回一个大于k的数 35 } 36 if(pos>=0) used[pos] = true; 37 ++cnt; 38 } 39 return cnt; 40 } 41 ll binary() 42 { 43 ll left=Min, right=sum, mid; 44 while(left<right) 45 { 46 mid = (left+right)>>1;//右移1位,就是/2 47 // cout << left << " " << right << " " << mid << endl; 48 if(div(mid)<=k) 49 right=mid; 50 else 51 left=mid+1; 52 } 53 return right; 54 } 55 56 inline void output() 57 { 58 int cnt = div(ans); 59 for(int i=0; i<m-1 && cnt<k; i++) 60 if(!used[i]) 61 { 62 used[i]=true; 63 ++cnt; 64 } 65 FOR(i, 0, m) 66 { 67 if(i) printf(" %lld",arr[i]); 68 else pf(arr[i]); 69 if(used[i]) 70 { 71 printf(" /"); 72 } 73 } 74 cout << endl; 75 } 76 int main() 77 { 78 int T; 79 sc(T); 80 while(T--) 81 { 82 sc2(m, k); 83 sum=0; 84 Min=0; 85 FOR(i, 0, m) 86 { 87 sc1(arr[i]); 88 sum += arr[i]; 89 if(arr[i]>Min) Min=arr[i]; 90 } 91 ans= binary(); 92 output(); 93 } 94 return 0; 95 }
还是有很多地方需要考虑,二分的思想很重要,重要是在div()中