一、题目
1、题目描述
2、输入输出
2.1输入
2.2输出
3、原题链接
E - Level Up |
二、解题报告
1、思路分析
碎碎念
赛时看出了单调性,想到了树状数组二分,然而题目说等级比怪高怪会跑,我看成了等级比怪高才能打怪,唉,卡E卡了一小时,没能上大分
分析过程:
首先,值域在 2e5 而不是 1e9,说们本题存在和值域挂钩的做法
考虑在线没法做,应该得离线处理
由于是离线,想了下分块,但也只是想了下,然后接着观察条件
k = x,那么我们从头开始打,等级最高是 floor(n / x) + 1
要素察觉,应该会涉及调和级数枚举,然后接着分析
我们固定x,下标 i 处等级升级为LV,假设在下标 j 处等级升级为LV + 1,那么[i + 1, j]内恰好有x个数字的值 >= LV
假如我们把升级下标称为border,那么每个x,border的数目不超过 n / x,那么所有x的border数目之和不超过n ln n
如果当前等级为1,那么数组中所有怪都能打,因为他们都 >= 1,当我们升级为2级,我们将数组中所有等级为1的怪删去,那么剩下的怪又是全都能打的
考虑每个怪只会被删一次,这个是O(N)的,显然又涉及到了区间和维护,考虑树状数组
现在将已知信息综合,有如下做法来预处理每个 x 能够到达的所有等级以及升级下标:
外层循环枚举等级1~n,初始能够考虑的 k 为[1, n]
当前枚举等级为LV
考虑k = x,升级为LV时的下标为cur,找升级为LV + 1时的下标
由于数组中剩下的都是能打的,所以直接二分找到下标
考虑相当于找sum(j) - sum(cur) = x,相当于在树状数组中找第sum(cur) + x小的位置,我们可以用树状数组二分找第k小优化掉一个log(当然不优化也能过)
如果找到,就将 j 存入,把x加入下一次循环的k集合
然后处理完LV,将值为LV的怪兽都删掉,每个怪兽最多只被删一次,所以是O(NlogN)的
整体时间复杂度:O(NlnNlogN)
2、复杂度
时间复杂度: O(N lnN logN)空间复杂度:O(NlnN)
3、代码详解
#include <bits/stdc++.h>
// #define DEBUG
using i64 = long long;
using u32 = unsigned;
using u64 = unsigned long long;
constexpr int inf32 = 1e9 + 7;
template<typename T = int>
class FenWick {
private:
int n;
std::vector<T> tr;
public:
FenWick(int _n) : n(_n), tr(_n + 1)
{}
FenWick(const std::vector<T> &_init) : FenWick(_init.size()) {
init(_init);
}
void init(const std::vector<T> &_init) {
for (int i = 1; i <= n; ++ i) {
tr[i] += _init[i - 1];
int j = i + (i & -i);
if (j <= n)
tr[j] += tr[i];
}
}
void add(T x, T k) {
for (; x <= n; x += x & -x) tr[x] += k;
}
void add(T l, T r, T k) {
add(l, k), add(r + 1, -k);
}
T query(T x) const {
T res = T{};
for (; x; x &= x - 1) res += tr[x];
return res;
}
T query(T l, T r) const {
if (l > r) return T{};
return query(r) - query(l - 1);
}
int select(const T &k) {
int x = 0;
T cur{};
for (int i = 1 << std::__lg(n); i; i /= 2) {
if (x + i <= n && cur + tr[x + i] <= k) {
x += i;
cur = cur + tr[x];
}
}
return x;
}
};
constexpr int N = 2e5 + 10;
std::vector<int> val[N];
std::vector<int> lvl_up[N], rem;
void solve() {
int n, q;
std::cin >> n >> q;
std::vector<int> a(n);
for (int i = 0; i < n; ++ i) {
std::cin >> a[i];
val[a[i]].push_back(i + 1);
}
for (int i = 1; i <= n; ++ i) {
rem.push_back(i); //对于lv=0,所有x都能考虑
lvl_up[i].push_back(0); //上一个位置都是0
}
FenWick tr(std::vector<int>(n, 1));
for (int lv = 1; lv <= n; ++ lv) {
std::vector<int> nrem;
for (int x : rem) {
int cur = lvl_up[x].back();
if (cur == n) continue;
int hi = tr.select(tr.query(cur) + x);
if (hi <= n) {
lvl_up[x].push_back(hi);
nrem.push_back(x);
}
}
rem = std::move(nrem);
for (int i : val[lv])
tr.add(i, -1);
}
while (q --) {
int i, x;
std::cin >> i >> x;
-- i;
if (lvl_up[x].size() <= a[i] || lvl_up[x][a[i]] > i)
std::cout << "YES\n";
else
std::cout << "NO\n";
}
}
auto FIO = []{
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
std::cout.tie(nullptr);
return 0;
} ();
int main() {
#ifdef DEBUG
freopen("in.txt", "r", stdin);
freopen("out.txt", "w", stdout);
#endif
int t = 1;
// std::cin >> t;
while (t --)
solve();
return 0;
}