文章目录

洛谷 P9870 双序列拓展 做题笔记

发布于

题目

题解

考虑一个计算量 $nm$ 的 DP,设 $f_{i, j}$ 表示能否让 $x_i$ 与 $y_j$ 匹配。转移为

$$f_{i, j} = \left(x_i < y_j\right) \land \left(f_{i - 1, j} \vee f_{i, j - 1} \vee f_{i - 1, j - 1}\right)$$

可以看作在一个 $A_{i, j} = \left[x < y_j\right]$ 的网格上走,问能否从 $\left(1, 1\right)$ 走到 $\left(n, m\right)$。不能走到的话,肯定是因为中间被封死了,有一下四中情况:

  1. $\exists i, A_{i, *} = 0$
    此时要求 $x_i \geq y_*$,即 $\max\limits_{1 \leq k \leq n} x_k \geq \max\limits_{1 \leq k \leq m} y_k$
  2. $\exists j, A_{*, j} = 0$
    此时要求 $x_* \geq y_j$,即 $\min\limits_{1 \leq k \leq n} \geq \min\limits_{1 \leq k \leq m} y_k$
  3. $\exists \left(i, j\right), A_{i, \leq j} = 0, A_{\leq i, j} = 0$
    此时要求 $x_i \geq \max\limits_{1 \leq k \leq j} y_k$ 且 $y_j \leq \min\limits_{1 \leq k \leq i} x_k$。
  4. $\exists \left(i, j\right), A_{i, \geq j} = 0, A_{\geq i, j} = 0$
    此时要求 $x_i \geq \max\limits_{j \leq k \leq m} y_k$ 且 $y_j \leq \min\limits_{i \leq k \leq n} x_k$。

情况 1 和情况 2 容易判断,情况 3 和情况 4 是类似的,我们只讨论情况 3 的处理方法。

我们可以枚举 $i$,我们希望找到一个最小的 $j$,满足 $y_j \leq \min\limits_{1 \leq k \leq i} x_k$,因为更大的 $j$,只会让 $\max\limits_{1 \leq k \leq j} y_k$ 更大,可能使得原本 $x_i \geq \max\limits_{1 \leq k \leq j} y_k$ 的点没有被检测到。我们发现,随着 $i$ 的增大,$j$ 单调不降,于是可以双指针,在 $O\left(n + m\right)$ 的复杂度内判断。

代码

int WITHERING([[maybe_unused]] int TEST_NUMBER) {
   tp c, n, m, q; cin >> c >> n >> m >> q;
   auto a = vcc(ZERO, n);
   auto b = vcc(ZERO, m);
   rar(ALL(a));
   rar(ALL(b));
   auto det = [](vector<tp> x, vector<tp> y) -> bool {
      if (x.front() == y.front()) return false;
      tp n = x.size();
      tp m = y.size();
      auto xmn = x;
      auto ymx = y;
      auto ymn = y;
      for (tp i = 1; i < n; ++i) xmn[i] = min(x[i], xmn[i - 1]);
      for (tp i = 1; i < m; ++i) ymn[i] = min(y[i], ymn[i - 1]);
      for (tp i = 1; i < m; ++i) ymx[i] = max(y[i], ymx[i - 1]);
      if (xmn.back() >= ymn.back()) return false;
      if (*max_element(ALL(x)) >= ymx.back()) return false;
      tp ptr = 0;
      for (tp i = 0; i < n; ++i) {
         while (ptr + 1 < m && ymn[ptr] > xmn[i]) ++ptr;
         if (ymn[ptr] <= xmn[i] && x[i] >= ymx[ptr]) return false;
      }
      xmn.back() = x.back();
      ymn.back() = y.back();
      ymx.back() = y.back();
      for (tp i = n - 2; i >= 0; --i) xmn[i] = min(x[i], xmn[i + 1]);
      for (tp i = m - 2; i >= 0; --i) ymn[i] = min(y[i], ymn[i + 1]);
      for (tp i = m - 2; i >= 0; --i) ymx[i] = max(y[i], ymx[i + 1]);
      ptr = m - 1;
      for (tp i = n - 1; i > 0; --i) {
         while (ptr - 1 >= 0 && ymn[ptr] > xmn[i]) --ptr;
         if (ymn[ptr] <= xmn[i] && x[i] >= ymx[ptr]) return false;
      }
      return true;
   };
   cout << (a.front() < b.front() ? det(a, b) : det(b, a));
   while (q--) {
      tp ka, kb; cin >> ka >> kb;
      auto _a = a;
      auto _b = b;
      while (ka--) {
         tp x, y; cin >> x >> y;
         _a[x - 1] = y;
      }
      while (kb--) {
         tp x, y; cin >> x >> y;
         _b[x - 1] = y;
      }
      cout << (_a.front() < _b.front() ? det(_a, _b) : det(_b, _a));
   }
   cout << '\n';
   return 0;
}

暂无评论

发表评论