Article Index

HDU 7511 创作乐曲 做题笔记

Published on

题意

给定 $n, m, k$ 和一个长度为 $n$ 的数组 $a$,满足 $1 \leq a_i \leq m$。

处理 $q$ 个询问,每次询问在 $\left[l, r\right]$ 中,至少删除几个数,能使得删完后的数组里,任意两个相邻的数的绝对值之差都不超过 $k$。

$1 \leq n \leq 10^5, 1 \leq q \leq 500$

题解

考虑对于每个询问暴力跑 DP,$f_i$ 表示以第 $i$ 个数结尾,最多能保留几个。离散化后用线段树维护可以达到 $O \left(qn \log n\right)$ 的复杂度。

但是我们有一个性质:对于一个值为 $a_i$ 的数,在最优解中,接在其后面的数只有两种可能,离 $i$ 最近的在 $\left[a_i - k, a_i\right]$ 内的数和离 $i$ 最近的在 $\left[a_i, a_i + k\right]$ 内的数。可以用 std::set 或者 线段树 平衡树 预处理。

对于每个询问,根据上述性质跑 DP 即可达到 $O\left(n \log n + nq\right)$ 的复杂度。

代码

/* C++17 is required!
 * By Koicy (https://koicy.ly)
 * Email n@rbtr.ee
 * 我还期待着名为奇迹的魔法,哪怕会凋零会消散只会是一场浮华,我笑纳!

         __    __                             __         _
   _____/ /_  / /_________  ___              / /______  (_)______  __
  / ___/ __ \/ __/ ___/ _ \/ _ \   ______   / //_/ __ \/ / ___/ / / /
 / /  / /_/ / /_/ /  /  __/  __/  /_____/  / ,< / /_/ / / /__/ /_/ /
/_/  /_.___/\__/_/   \___/\___/           /_/|_|\____/_/\___/\__, /
                               SIGN                         /___*/
#define __NO_MAIN__ false
#define __ENABLE_RBLIB__ true
constexpr bool _MTS = true, SPC_MTS = false;
constexpr char EFILE[] = "";
#include <bits/stdc++.h>
#define FULL(arg) arg.begin(), arg.end()

// :/

using namespace std;
using tp = long long int;
using vetp = basic_string<tp>;
[[maybe_unused]] constexpr tp ZERO = 0, ONE = 1, INF = -1ull >> 2;
signed STRUGGLING(unsigned long long int);
void MIST();
#if !__NO_MAIN__
int main(int argc, char* argv[]) {
  unsigned long long int t = 0, _t = 1;
  MIST();
  if (_MTS && !SPC_MTS) cin >> _t;
  while (t < _t || SPC_MTS) {
    if (STRUGGLING(++t) != 0) return 0;
  }
  return 0;
}
#endif
#ifdef XCODE
#define bg(...){cout<<"["<<__LINE__<<'@'<<++_LT[__LINE__]<<':';BG(__VA_ARGS__);}
size_t _LT[21777]; template<typename _Type>void BG(const _Type&_cur){cout<<' '<<
_cur << ']' << " <<:" << endl; } template<typename _Type,typename... _Other>void
BG(const _Type& _cur, const _Other& ..._other) {cout<< ' '<<_cur;BG(_other...);}
#else
#define bg(...)
#define dputs(...)
#endif

// :/

// :/

signed STRUGGLING([[maybe_unused]] unsigned long long int TEST_NUMBER) {
  tp n, m, k; cin >> n >> m >> k;
  vetp a(n + 1, 0);
  for (tp i = 1; i <= n; ++i) cin >> a[i];
  vetp id(n + 1, 0); iota(1 + FULL(id), 1);
  vetp prv(n + 1, 0);
  vetp nxt(n + 1, 0);
  stable_sort(FULL(id), [&](tp x, tp y) { return a[x] < a[y]; });
  [&]() {
    tp p = n;
    set<tp> s;
    for (tp i = n; i >= 1; --i) {
      s.insert(id[i]);
      while (a[id[p]] - a[id[i]] > k) s.erase(id[p--]);
      if (auto it = s.upper_bound(id[i]); it != s.end()) prv[id[i]] = *it;
    }
  }();
  [&]() {
    tp p = 1;
    set<tp> s;
    for (tp i = 1; i <= n; ++i) {
      s.insert(id[i]);
      while (a[id[i]] - a[id[p]] > k) s.erase(id[p++]);
      if (auto it = s.upper_bound(id[i]); it != s.end()) nxt[id[i]] = *it;
    }
  }();
  tp q; cin >> q;
  while (q--) {
    tp l, r; cin >> l >> r;
    vetp f(n + 1, 1);
    for (tp i = l; i <= r; ++i) {
      for (auto& t : { prv[i], nxt[i] }) {
        if (l <= t && t <= r) f[t] = max(f[t], f[i] + 1);
      }
    }
    cout << r - l + 1 - *max_element(FULL(f)) << '\n';
  }
  return 0;
}

void MIST() {
  cin.tie(nullptr)->sync_with_stdio(false);
}

// :\ */

No comments

Post a comment