二分:切巧克力
切巧克力
www.acwing.com/problem/content/1229/

-
利用二分,规定每次切割的最大边长为多少 O ( l o g n ) O(logn) O(logn)
-
其实就相当于暴力枚举,但是二分比线性枚举效率更高
-
为何可以二分:二段性
- 若 mid 满足条件,那么比 mid 小的数一定都成立;比 mid 大的数不都成立 -> [mid, r]
- 若 mid 不满足条件,那么比 mid 小的数不都成立;比 mid 大的数都不成立 -> [l, mid - 1]
- 无论是 mid 满足条件还是不满足条件,都能将下次判断的区间变为 1/2
-
-
只能切割不能拼接,所以每个长方形的切割都是独立的 O ( n ) O(n) O(n)
∑ i = 0 n − 1 ⌊ h i m i d ⌋ ∗ ⌊ w i m i d ⌋ \sum _{i=0}^{n-1} \lfloor \frac{h_i}{mid} \rfloor *\lfloor \frac{w_i}{mid} \rfloor i=0∑n−1⌊midhi⌋∗⌊midwi⌋
最后时间复杂度为 O ( n l o g n ) O(nlogn) O(nlogn)
import java.io.*;
public class Main {
private static int N = 100010;
private static int[] h = new int[N];
private static int[] w = new int[N];
private static int n, k;
public static void main(String[] args) throws Exception {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String[] input = br.readLine().split(" ");
n = Integer.parseInt(input[0]);
k = Integer.parseInt(input[1]);
for (int i = 0; i < n; i++) {
input = br.readLine().split(" ");
h[i] = Integer.parseInt(input[0]);
w[i] = Integer.parseInt(input[1]);
}
int left = 1, right = N;
while (left < right) {
int mid = left + right + 1 >> 1;
if (check(mid)) {
// 数额大于等于k,找右半部分
left = mid;
} else {
// 数额小于k,找左半部分
right = mid - 1;
}
}
System.out.println(left);
}
// 切边长为x能切出多少块
private static boolean check(int x) {
long sum = 0;
for (int i = 0; i < n; i++) {
// 可能会超出数据范围 10^5 * 10^5
sum += (long)(h[i] / x) * (w[i] / x);
if (sum >= k) {
return true;
}
}
return false;
}
}
二分法解决切巧克力问题
152

被折叠的 条评论
为什么被折叠?



