CF2124H Longest Good Subsequence

考虑直接对于 \(b\) 进行刻画。

注意到,对于一个 \(i\),有 \(b_{b_i}=b_i\),考虑对于 \(b_x=x\) 的点 dp,称这些点为关键点。

\(f_{l,r}\) 表示现在考虑 \([l,r]\),且 \(l\) 是第 \(a_l\) 个选的位置。

转移如果 \(r\) 未选就 \(f_{l,r-1}\to f_{l,r}\)。否则枚举一个关键点 \(p\),如果 \(f_{l,p}\ge a_p-1\)\(f_{p,r}\to f_{l,r}\)。直接实现可以 \(O(n^3)\)

考虑优化,根据上面的分析有子序列位置 \(a_r\) 上的点一定是关键点,因此我们只需要考虑那些 \(a_p=a_r\) 的转移,此时只要保留最小的 \(p\) 即可。时间复杂度 \(O(n^2)\)

#include <bits/stdc++.h>
using namespace std;

const int kN = 1.5e4 + 5;
int n;
int a[kN];
short f[kN][kN], pos[kN];

void Solve() {
  cin >> n;
  for(int i = 1; i <= n; i++) cin >> a[i];
  for(int i = 0; i <= n; i++) {
    fill_n(f[i], n + 3, -n);
  }
  for(int l = n; ~l; l--) {
    f[l][l] = a[l];
    fill_n(pos, n + 3, 0);
    for(int r = l + 1; r <= n; r++) {
      f[l][r] = f[l][r - 1] + (a[r] == a[l]);
      if(a[r] < a[l]) continue;
      if(!pos[a[r]] && (f[l][r - 1] >= a[r] - 1)) {
        pos[a[r]] = r;
      }
      if(pos[a[r]]) {
        f[l][r] = max(f[l][r], f[pos[a[r]]][r]);
      }
    }
  }
  cout << f[0][n] << "\n";
}

int main() {
  // freopen("1.in", "r", stdin);
  // freopen("1.out", "w", stdout);
  ios::sync_with_stdio(0), cin.tie(0);
  int t;
  cin >> t;
  while(t--) Solve();
  return 0;
}
posted @ 2025-12-09 16:48  CJzdc  阅读(2)  评论(0)    收藏  举报