这是一道裸的二分题
题意
有n个电脑,每个电脑有
a
i
a_i
ai的电,每个电脑一分钟用
b
i
b_i
bi的电,每次可以给一个电脑充
x
x
x的电,电脑最后一次的电可以是负数,但必须满足前一次每台电脑的电都是正数,一共要坚持
k
k
k分钟.
n
,
a
i
,
b
i
,
k
n,a_i,b_i,k
n,ai,bi,k均给出,求
x
x
x的最小值.
思路
这种题,看到就会想到要二分这个
x
x
x的值,那么接下来就考虑如何
c
h
e
c
k
(
)
check()
check()这个这个x值.
考虑使用一个优先队列,按照可以撑的时间排序,每次给可以撑的时间最少的点加上
x
x
x的电,然后每当有可以超过
k
k
k的,就直接移出队列,当队列为空时,便为成功,然后继续二分即可.
代码
具体实现见代码
#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
#include <cmath>
#include <cctype>
#include <algorithm>
#include <vector>
namespace OI
{
#define pk putchar(' ')
#define ph puts("")
#define fi first
#define se second
template<class T>
void rd(T &x)
{
x = 0;
int f = 1;
char c;
while (!isdigit(c = getchar())) if (c == '-') f = -1;
do
{
x = (x << 3) + (x << 1) + (c ^ 48);
} while (isdigit(c = getchar()));
x *= f;
}
template<class T>
void pt(T x)
{
if (x < 0)
putchar('-'), x = -x;
if (x > 9)
pt(x / 10);
putchar(x % 10 ^ 48);
}
}
using namespace OI;
using namespace std;
typedef long long ll;
const int N = 2e5 + 5;
const ll INF = 2e12;
int n, k;
ll a[N], l, r, ans, b[N];
struct node
{
ll a, b, c;
bool operator < (const node &x)const{
if (c != x.c)
return c > x.c;
if (b != x.b)
return b < x.b;
return a > x.a;
}
};
priority_queue<node> Que;
bool check(ll x)
{
while (!Que.empty()) Que.pop();
for (int i = 1; i <= n; i++)
if (a[i] / b[i] < k)
Que.push({a[i], b[i], a[i] / b[i]});
if (Que.empty())
return 1;
for (int i = 0; i < k; i++)
{
node t = Que.top();
Que.pop();
if (t.c < i)
return 0;
if ((t.a + x) / t.b < k)
Que.push({t.a + x, t.b, (t.a + x) / t.b});
if (Que.empty())
return 1;
}
return 1;
}
int main()
{
rd(n), rd(k);
for (int i = 1; i <= n; i++)
rd(a[i]);
for (int i = 1; i <= n; i++)
rd(b[i]);
l = 0, r = INF, ans = -1;
while (l <= r)
{
ll mid = (l + r) >> 1;
if (check(mid))
ans = mid, r = mid - 1;
else
l = mid + 1;
}
pt(ans);
return 0;
}