洛谷 P3287

不难发现一定是拔高一段后缀。

所以设 fi,j 表示考虑前 i 个位置,拔高 j 次,第 i 个位置强制选的 LIS 的长度。

则有 fi,j=max1x<i,0yj,ax+yai+j{fx,y+1}

x<i 天然满足,而剩下两个条件可以用二维 BIT 优化。

因为 j 可以为 0 所以要整体右移一位。

而且不难发现为了不让同一个 i 之间转移所以像背包一样 j 倒序枚举。

时间复杂度 O(nklogklogw),只能说非常离谱。

Code:

#include <bits/stdc++.h>
using namespace std;
const int N = 10005, M = 5005, K = 505;

void chkmax(int &a, int b) { if (a < b) a = b; }

int n, m;
int a[N], f[N][K], c[K][K+M];

void upd(int x, int y, int v) {
	for (int i = x; i <= m + 1; i += i & -i)
		for (int j = y; j <= 5500; j += j & -j) chkmax(c[i][j], v);
}

int query(int x, int y) {
	int res = 0;
	for (int i = x; i; i -= i & -i)
		for (int j = y; j; j -= j & -j) chkmax(res, c[i][j]);
	return res;
}

int main() {
	scanf("%d%d", &n, &m);
	for (int i = 1; i <= n; ++i) scanf("%d", &a[i]);
	for (int i = 1; i <= n; ++i)
		for (int j = m; ~j; --j)
			upd(j + 1, a[i] + j, f[i][j] = query(j + 1, a[i] + j) + 1);
	printf("%d", query(m + 1, 5500));
	return 0;
}
posted @   Kobe303  阅读(20)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
点击右上角即可分享
微信分享提示