BZOJ 3594

有一个长为n的序列,你可以进行k次区间+1,求LIS。

$$n leq 10000,k leq 500, 1 leq a_i leq 5000$$

首先发现每次+1的区间必然是一个后缀,设f(i,j)为以第i个数结尾,+1了j次的长度,转移是显然的,用二维BIT优化转移就能过了。

const int MAXN = 10000 + 5, MAXM = 5000 + 5, MAXK = 500 + 5;

struct BinaryIndexedTree2D {
  int arr[MAXK][MAXM + MAXK], n, m;
  
#define lowbit(x) ((x) & -(x))
  void modify(int a, int b, int x) {
    ++ a;
    for (int i = a; i <= n; i += lowbit(i))
      for (int j = b; j <= m; j += lowbit(j))
        chkmax(arr[i][j], x);
  }
  
  int query(int a, int b) {
    ++ a;
    int ans = 0;
    for (int i = a; i; i -= lowbit(i))
      for (int j = b; j; j -= lowbit(j))
        chkmax(ans, arr[i][j]);
    return ans;
  }
} T;

int a[MAXN], f[MAXK], lis[MAXN], g[MAXN];

int main() {
  int n, k;
  scanf("%d%d", &n, &k);
  int max = 0;
  For(i, 1, n) {
    scanf("%d", &a[i]);
    chkmax(max, a[i]);
  }
  T.n = k + 1, T.m = max + k;
  memset(g, 63, sizeof g);
  g[0] = 0;
  int ans = 0;
  For(i, 1, n) {
    int k = std::upper_bound(g, g + n + 1, a[i]) - g;
    lis[i] = k, g[k] = a[i];
    chkmax(ans, lis[i]);
  }
  For(i, 1, n) {
    Rep(j, k, 1) {
      f[j] = T.query(j, a[i] + j) + 1;
      T.modify(j, a[i] + j, f[j]);
      chkmax(ans, f[j]);
    }
    T.modify(0, a[i], lis[i]);
  }
  printf("%d
", ans);
  return 0;
}
原文地址:https://www.cnblogs.com/sjkmost/p/9769134.html