链接:
题目大意:
可以 (k) 次区间加一数列 (a),求最长不下降子序列长度。
正文:
最重要的一点是,区间加一操作的右端点一定是 (n)。假设原本想要区间 ([l,r]) 加一,由于是求最长不下降子序列长度,所以 ([l,r]) 加一后,肯定也小于等于 ([r+1,n]) 的任意一点,所以直接 ([l,n]) 对答案没有影响。
接着就是设 (f_{i,j}) 表示 (a_i) 被加过 (j) 次的最长不下降子序列长度,则有:
[f_{i,j}=max_{k<i,lleq j,a_k+l<a_i+j}{f_{k,l}+1}
]
可以用二维的树状数组维护。
代码:
int n, mx, m;
int t[M][N], ans;
int a[N];
void update(int x, int k, int val)
{
for (; x <= mx; x += x & -x)
for (int i = k; i <= m + 1; i += i & -i)
t[i][x] = max(t[i][x], val);
}
int query(int x, int k)
{
int ans = 0;
for (; x; x -= x & -x)
for (int i = k; i; i -= i & -i)
ans = max(t[i][x], ans);
return ans;
}
int main()
{
scanf ("%d%d", &n, &m);
memset (t, 0, sizeof t);
for (int i = 1; i <= n; i++)
scanf ("%d", &a[i]), mx = max(mx, a[i]);
mx += m;
for (int i = 1; i <= n; i++)
for (int j = m; ~j; j--)
{
int tmp = query(a[i] + j, j + 1) + 1;
ans = max(ans, tmp);
update(a[i] + j, j + 1, tmp);
}
printf ("%d
", ans);
return 0;
}