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\n", 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\n", 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 }
来源:https://www.cnblogs.com/romaLzhih/p/12333352.html