1 条题解
-
0
题意简述
有 只怪兽按顺序排列,第 只怪兽的等级为 。
Monocarp 初始等级为 ,他需要依次面对这些怪兽。
存在一个参数 ,Monocarp 每击败一只怪兽,等级就会增加 。
对于第 只怪兽,如果在他到达之前 Monocarp 的等级已经 ,则怪兽会逃跑(不计算击败,也不增加等级);否则 Monocarp 必须击败它,等级 。
给定 个询问,每个询问给出 和 ,问当参数为 时,第 只怪兽是否会逃跑。思路分析
关键观察
- 越小,Monocarp 升级越慢,越容易在遇到某只怪兽时等级不够,从而必须战斗,导致后续等级增长更慢。
- 反过来, 越大,升级越快,怪兽更容易逃跑。
- 因此,对于每只怪兽 ,存在一个阈值 :
当 时,怪兽 会逃跑;当 时,怪兽 会战斗。
问题转化
我们需要对每个 求出 。
怪兽 逃跑的充要条件是:在遇到它之前,Monocarp 已经击败了至少 只怪兽。
因为每击败一只怪兽等级 +1,当等级 时怪兽逃跑,而等级 = 已击败数量 / (向下取整?需要仔细分析)准确条件推导
设 为 之前实际击败的怪兽数。
Monocarp 的等级 = 。
怪兽 逃跑 $\iff \lfloor p/k \rfloor \ge a_i \iff p \ge a_i \cdot k$。
所以条件是: 之前至少有 只怪兽被打败。二分 + 树状数组求
- 对每个 ,二分 的值,判断在 下怪兽 是否会逃跑。
- 判断时,需要知道在 之前有多少怪兽被打败。这取决于之前的怪兽是否逃跑,而之前的逃跑又依赖于 。
- 因此我们按顺序处理 ,维护一个树状数组,下标为 ,值为逃跑的怪兽数量对应的某种前缀信息。
具体地:我们二分 ,并用树状数组快速查询当 取某个值时,前 只怪兽中逃跑的数量,从而得到被打败的数量 。
然后判断 。
算法步骤
- 初始化树状数组为空。
- 对 到 :
- 二分最小的 使得怪兽 逃跑(即找到 )。
- 将 插入树状数组(表示对于这个 值,有一只怪兽会逃跑)。
- 存储 。
- 回答询问:如果 输出
"YES",否则"NO"。
时间复杂度
- 预处理:
- 每个询问:(直接比较阈值)
- 优化后可达
AC 代码(优化版)
#include <iostream> #include <tuple> using namespace std; const int N = 4e5 + 10; int a[N], n, q, tr[N], req[N], cur; template <typename _Tp> inline void read(_Tp &x) { char ch; while (ch = getchar(), !isdigit(ch)); x = ch - '0'; while (ch = getchar(), isdigit(ch)) x = (x << 3) + (x << 1) + (ch ^ '0'); } template <typename _Tp, typename... _Args> inline void read(_Tp &x, _Args &...args) { read(x); read(args...); } inline void update(int x, int v) { while (x < N) { tr[x] += v; x += (x & -x); } } int main() { read(n, q); for (int i = 1; i <= n; i++) read(a[i]); for (int i = 1; i <= n; i++) { int l = 0, cur = 0; for (int j = 17; ~j; j--) { int nxt = l | (1 << j); if (1ll * a[i] * nxt <= cur + tr[nxt]) { l = nxt; cur += tr[nxt]; } } l++; update(l, 1); req[i] = l; } for (int i = 1, x, k; i <= q; i++) { read(x, k); puts(k < req[x] ? "NO" : "YES"); } return 0; }
- 1
信息
- ID
- 6935
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 10
- 标签
- 递交数
- 1
- 已通过
- 1
- 上传者