二分:切巧克力

二分法解决切巧克力问题

二分:切巧克力

切巧克力

www.acwing.com/problem/content/1229/

在这里插入图片描述

  1. 利用二分,规定每次切割的最大边长为多少 O ( l o g n ) O(logn) O(logn)

    1. 其实就相当于暴力枚举,但是二分比线性枚举效率更高

    2. 为何可以二分:二段性

      1. 若 mid 满足条件,那么比 mid 小的数一定成立;比 mid 大的数不都成立 -> [mid, r]
      2. 若 mid 不满足条件,那么比 mid 小的数不都成立;比 mid 大的数都不成立 -> [l, mid - 1]
      3. 无论是 mid 满足条件还是不满足条件,都能将下次判断的区间变为 1/2
  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=0n1midhimidwi

最后时间复杂度为 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;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值