POJ3258
题意:
有一堆牛要过河,河的长度是 L,河中间有N个石头,牛只能踩着石头过河,问去掉M个石头后(去掉这M个石头的方式是随机的),牛能走的石头间距最小值中,最大的那一个是多少,输出距离。
开始和最后的两块石头不能搬走。
解法:
最大化石头间距的最小值
二分距离,从左到右遍历所有的石头(包括首尾),在判断距离之内不停的搬走石头,当石头总数大于M的时候即是错误。
代码如下:
1 int L, M, N; 2 int pos[MAXN]; 3 4 bool C(int x) { 5 int sum = 0, last = 0; 6 for (int i = 1; i <= N + 1; i++) { 7 if (pos[i] - pos[last] < x) { 8 sum++; 9 if (sum > M) { 10 return false; 11 } 12 } else { 13 last = i; 14 } 15 } 16 return true; 17 } 18 19 void jojo() { 20 sort(pos, pos + N + 1); 21 int lb = 0, ub = L + 1; 22 while (ub - lb > 1) { 23 int mid = (ub + lb) / 2; 24 if (C(mid)) { 25 // cout << "true: " << mid << endl; 26 lb = mid; 27 } else { 28 // cout << "false: " << mid << endl; 29 ub = mid; 30 } 31 } 32 cout << lb << endl; 33 } 34 35 int main() { 36 #ifndef ONLINE_JUDGE 37 freopen("input.txt", "r", stdin); 38 #endif // !ONLINE_JUDGE 39 L = READ(), N = READ(), M = READ(); 40 for (int i = 1; i <= N; i++) pos[i] = READ(); 41 pos[0] = 0; 42 pos[N + 1] = L; 43 jojo(); 44 return 0; 45 }
POJ3273
题意:
有N个数,要求按顺序划分成M组,使得这M组数的和的最大值最小。
解法:
最小化最大值
二分M组数的和,遍历所有的数,累加,当其大于二分值的时候将计数器加1,当最后如果计数器的值大于M,则为非法。
这里其实有两种情况,假如要准确划分7组:
1. 那么假如前面的划分成 3 组之后,后面一共3个数,每个都小于二分值,但不够分成 4 组怎么办?
2. 或者前面已经划分成了 6 组,后面还有3个数,每个都超过了二分值,怎么办?
对于第一种情况:我们判定的是真,那么说明二分值可以进一步缩小。
对于第二种情况:那么肯定超过了M-1,所以返回false
还有一点注意的是,对于二分的值,如果我们想要缩小范围,那么请把上下界的范围扩大1,这样可以避免WA。
啧啧,简直了。
1 int N, M; 2 int d[MAXN]; 3 int mx, mn; 4 5 bool C(int x) { 6 int last = 0, num = 0, sum = 0; 7 for (int i = 0; i < N; i++) { 8 if (sum + d[i] <= x) { 9 sum += d[i]; 10 } else { 11 num++; 12 sum = d[i]; 13 } 14 } 15 if (num + 1 > M) { 16 return false; 17 } else { 18 return true; 19 } 20 } 21 22 void solve() { 23 int ub = mx + 1, lb = mn; 24 while (ub - lb > 1) { 25 int mid = (ub + lb) >> 1; 26 if (C(mid)) { 27 ub = mid; 28 } else { 29 lb = mid; 30 } 31 } 32 cout << ub << endl; 33 return; 34 } 35 36 int main() { 37 #ifndef ONLINE_JUDGE 38 freopen("input.txt", "r", stdin); 39 #endif // !ONLINE_JUDGE 40 while (scanf("%d%d", &N, &M) != EOF) { 41 mx = 0, mn = 0; 42 for (int i = 0; i < N; i++) { 43 scanf("%d", &d[i]); 44 mx += d[i]; 45 mn = min(mn, d[i]); 46 } 47 solve(); 48 } 49 return 0; 50 }
POJ3104
题意:
每件衣服都有一定单位水分,在不适用烘干器的情况下,每件衣服每分钟自然流失1个单位水分,但如果使用了烘干机则每分钟流失K个单位水分,但是遗憾是只有1台烘干机,每台烘干机同时只能烘干1件衣服,请问要想烘干N件衣服最少需要多长时间?
解法:
二分首先要先考虑是不是有单调关系,就是越怎么样就越怎么样。
这题,时间越多,就越可以烘干,所以二分时间。
先对水量排个序,每次二分时间 t,也就是说在没有烘干机的情况下,每件衣服可以减少 t 水分。那么比 t 小的衣服就不用烘干,比 t 大的就一定要烘干。
计算每一件衣服要烘干的时间,也就是$frac{a[i]-t}{k-1}$,因为这一分钟选择了烘干,意味着在原来基础上减去 k-1水分,然后有余数就要再多烘干一分钟。最后统计一下烘干时间是不是大于t就行了。
二分复杂度是log1e9,每次遍历是O(n),可过。
这题的锅:首先要用LL,因为最坏的情况k为2,水量全都1e9。然后特判一下k=1时,不然除0会re
1 LL N, K; 2 LL a[MAXN]; 3 LL mx = -1; 4 5 bool C(LL t) { 6 int i = lower_bound(a, a + N, t) - a; 7 LL sum = 0; 8 for (; i < N; i++) { 9 if ((a[i] - t) % (K - 1) == 0) { 10 sum += (a[i] - t) / (K - 1); 11 } else { 12 sum += ((a[i] - t) / (K - 1) + 1); 13 } 14 } 15 if (sum > t) { 16 return false; 17 } else { 18 return true; 19 } 20 } 21 22 void solve() { 23 sort(a, a + N); 24 if (K == 1) { 25 printf("%lld ", mx); 26 return; 27 } 28 LL ub = LLINF, lb = 0; 29 while (ub - lb > 1) { 30 LL mid = (ub + lb) >> 1; 31 if (C(mid)) { 32 ub = mid; 33 } else { 34 lb = mid; 35 } 36 } 37 printf("%lld ", ub); 38 return; 39 } 40 41 int main() { 42 #ifndef ONLINE_JUDGE 43 freopen("input.txt", "r", stdin); 44 #endif // !ONLINE_JUDGE 45 scanf("%lld", &N); 46 for (int i = 0; i < N; i++) { 47 scanf("%lld", &a[i]); 48 mx = max(a[i], mx); 49 } 50 scanf("%lld", &K); 51 solve(); 52 return 0; 53 }