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\n", ans); return 0; }