noi.ac #46. delete
SOLUTION
暴力做的话有一个 \(n \times k\) 的 \(DP\),dp[i][j]
表示只在前 \(i\) 个数字中删除, 删除了 \(j\) 个数字的最大 \(cnt\),当前面删除了 \(k\) 个之后,后面的数字是固定的,需要统计一下再 \(i\) 后面有多少个位置符合 i - k == a[i]
,此时答案就是 \(ans = dp[i][k] + \sum_{k=i+1}^{n} [i-k==a[i]]\),状态转移的时候考虑第 \(i\) 个位置删还是不删 dp[i][j] = max(dp[i-1][j-1], dp[i][j] + (a[i] == i - j));
因此可以得出一份 \(60\) 分的代码
void solve2() {
cin >> n >> k;
vector<int> a(n + 1);
int cnt = 0;
for (int i = 1; i <= n; i ++ ) {
cin >> a[i];
if (i > k) cnt += (i - a[i] == k);
}
vector<vector<int> > dp(n + 1, vector<int> (k + 1, 0));
int ans = 0;
for (int i = 1; i <= n; i ++ ) {
if (i > k) cnt -= (i - a[i] == k);
for (int j = 0; j <= min(i, k); j ++ ) {
if (j) dp[i][j] = dp[i - 1][j - 1];
dp[i][j] = max(dp[i][j], dp[i - 1][j] + (a[i] == i - j));
}
if (i >= k) {
chkmax(ans, dp[i][k] + cnt);
}
}
cout << ans << "\n";
}
下面可以通过本题的解法
考虑如果某个数字 a[i]
是不被删除的,并且它在最终的数字中是满足 a[i] = i
的.
那么它需要满足 \(a_i \le i, i - a_i \le k, k + a_i \le n\)
- 只有满足 \(a_i \le i\) ,
a[i] = i
才可能在删除某几个数字之后符合 - \(i - a_i \le k\) 删除的数字必须小于等于 \(k\) 个
- \(k + a_i \le n\) 必须保证如果在 \(i\) 前面没有删够 \(k\) 个,后面还有位置去删除
那么可以得到一个 \(n \log n\) 的 \(DP\)
dp[i]
表示最终的数组中有第 \(i\) 个位置并且这个位置在最终的数组中符合 a[i] = i
,此时的最大 \(cnt\) ,考虑如何去转移,可以将符合条件的位置按照需要删除的数字的个数排个序,那么
\[{dp}_i = \max{{dp}_j} + 1
\]
快速的找到 \({dp}_j\) 可以用树状数组维护前缀 \(max\)
代码如下
#include <bits/stdc++.h>
using namespace std;
#define rep(i, a, b) for (int i(a); i <= b; ++i)
#define dec(i, a, b) for (int i(b); i >= a; --i)
template <typename T>
void chkmax(T &x, T y) {
x = max(x, y);
}
template <typename T>
void chkmin(T &x, T y) {
x = min(x, y);
}
const int N = 1E6 + 10;
int n, k, m;
int a[N], dp[N];
pair<int, int> p[N];
template <typename T>
class fenwick {
public:
vector<T> fenw;
int n;
fenwick(int _n) : n(_n) { fenw.resize(n); }
void modify(int x, T v) {
while (x < n) {
chkmax(fenw[x], v);
x |= (x + 1);
}
}
T get(int x) {
T v = 0;
while (x >= 0) {
chkmax(v, fenw[x]);
x = (x & (x + 1)) - 1;
}
return v;
}
};
void solve() {
cin >> n >> k;
rep(i, 1, n) {
cin >> a[i];
if (a[i] <= i && i - a[i] <= k && a[i] <= n - k)
p[m++] = make_pair(i - a[i], a[i]);
}
sort(p, p + m);
fenwick<int> fen(n + 10);
for (int i = 0; i < m; i++) {
int now = fen.get(p[i].second - 1);
fen.modify(p[i].second, now + 1);
}
cout << fen.get(n);
}
int main() {
ios::sync_with_stdio(0);
cin.tie(0);
solve();
return 0;
}