题目描述

第一行输入共有N个同学,带了N个笔记本,N < 2e5 + 1,需要坚持 K 分钟。
第二行给出N个整数,每个整数代表笔记本初始电量,a[i] < 1e12 + 1
第三行给出N个整数,每个整数代表笔记本每分钟消好电量,b[i] < 1e7 + 1
现在你可以买一个充电器,再每分钟给某个笔记本充电 x 的电量,这个 x 最小是多少?如果永远无法满足那就输出 -1

Solution

稍微思考,可以发现这个答案 x 满足二分的性质,如果当前x可以,我是不是能买小一点的充电器呢?如果不行的就只能吧 x 变大了,所以可以二分这个答案去验证是否可以实现。
那么问题来到如何验证当前 x 是否可以使得全部机子活过 K 分钟。
那么每分钟充电一定是选坚持轮数最小的那一台机器,那么我们使用一个最小堆,把全部的需要充电才能活下来的机器放在最小堆里面去,最小堆的排序规则就是 越早死的排在越前面充电。
这个时候可以特判一下,如果堆中没有元素说明全部机子都可以活下来,不需要充电器,也就是当前 mid 可成立
在接下来枚举 k 分钟,每分钟选最小的机子充电,如果当前选出来的机器活不下来,那就是当前的充电器不合格。
再把充电之后的这个机器算一次可以活下多久,如果活不到 K 分钟就再塞进堆中,
循环 k 次过程中堆中再次没有元素了就还是 return true
完成 K 次循环也是返回 true

#pragma GCC target("avx,sse2,sse3,sse4,popcnt")
#pragma GCC optimize("O2,O3,Ofast,inline,unroll-all-loops,-ffast-math")
#include <bits/stdc++.h>
using namespace std;
#define js ios::sync_with_stdio(false);cin.tie(0); cout.tie(0)
#define all(__vv__) (__vv__).begin(), (__vv__).end()
#define endl "\n"
#define pai pair<ll, pair<ll, ll> >
#define ms(__x__,__val__) memset(__x__, __val__, sizeof(__x__))
typedef long long ll; typedef unsigned long long ull; typedef long double ld;
inline ll read() { ll s = 0, w = 1; char ch = getchar(); for (; !isdigit(ch); ch = getchar()) if (ch == '-') w = -1; for (; isdigit(ch); ch = getchar())    s = (s << 1) + (s << 3) + (ch ^ 48); return s * w; }
inline void print(ll x, int op = 10) { if (!x) { putchar('0'); if (op)    putchar(op); return; }    char F[40]; ll tmp = x > 0 ? x : -x;    if (x < 0)putchar('-');    int cnt = 0;    while (tmp > 0) { F[cnt++] = tmp % 10 + '0';        tmp /= 10; }    while (cnt > 0)putchar(F[--cnt]);    if (op)    putchar(op); }
inline ll gcd(ll x, ll y) { return y ? gcd(y, x % y) : x; }
ll qpow(ll a, ll b) { ll ans = 1;    while (b) { if (b & 1)    ans *= a;        b >>= 1;        a *= a; }    return ans; }    ll qpow(ll a, ll b, ll mod) { ll ans = 1; while (b) { if (b & 1)(ans *= a) %= mod; b >>= 1; (a *= a) %= mod; }return ans % mod; }
inline int lowbit(int x) { return x & (-x); }
const int dir[][2] = { {0,1},{1,0},{0,-1},{-1,0},{1,1},{1,-1},{-1,1},{-1,-1} };
const int MOD = 1e9 + 7;
const int INF = 0x3f3f3f3f;

const int N = 2e5 + 7;
ll n, k, a[N], b[N];

bool check(ll x) {
    priority_queue<pai, vector<pai>, greater<pai>> pq;
    for (int i = 1; i <= n; ++i)
        if (a[i] / b[i] < k)
            pq.push({ a[i] / b[i],{a[i],b[i]} });
    if (pq.empty())    return true;
    for (int i = 0; i < k; ++i) {
        ll C = pq.top().first, A = pq.top().second.first, B = pq.top().second.second;    pq.pop();
        if (C < i)    return false;
        if (A / B < k) {
            A += x;
            pq.push({ A / B,{A,B} });
        }
        if (pq.empty())    return true;
    }
    return true;
}

int main() {
    n = read(), k = read();
    for (int i = 1; i <= n; ++i)
        a[i] = read();
    for (int i = 1; i <= n; ++i)
        b[i] = read();
    ll l = 0, r = 1e13, ans = -1;
    while (l <= r) {
        ll mid = l + r >> 1;
        if (check(mid))
            ans = mid, r = mid - 1;
        else
            l = mid + 1;
    }
    print(ans);
    return 0;
}