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;
}
posted @ 2022-09-05 21:39  ccz9729  阅读(17)  评论(0编辑  收藏  举报