最大化最小值

穿精又带淫゛_ 提交于 2020-02-19 21:54:29

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 }

 

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!