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;
}
浙公网安备 33010602011771号