分析:我们可以用dp[i][j]表示i为结尾的使用了j点体力的最大值,因为分a和b,所以再加1维,dp[i][j][0]表示a,dp[i][j][1]表示b,然后状态转移方程是这样的
dp[i]j[j][0] = max{dp[k][j][0], k < i,a[k] < a[i]}, max(dp[k][j][1], k < i, b[k] < a[i]);
dp[i][j][1] = max{dp[k][j-1][0], k < i,a[k] < b[i]}, max(dp[k][j-1][1], k < i, b[k] < b[i]);
但是这样时间复杂度是指数级的
然后我们可以用把a,b数组离散化后用BIT记录使用了j点体力的最大值,先查询,然后更新BIT,这样就变成了n*m*logn,然后注意的是循环的顺序,外循环是从0到n,
内循环从m到0而不是从0到m。举例:a[0] = 1, b[0] = 2, 那么在内圈从0循环到1的时候b[0] 会利用a[0]的值扩大LIS,而这是错误的,a[0]和b[0]不可同时存在的。
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
const int N = 1009;
int nn;
int a[N],b[N];
int h[N * 2];
struct BIT{
int c[2*N];
int lowbit(int x){return x & -x;}
void update(int x, int k){
while(x <= nn){
c[x] = max(c[x], k);
x += lowbit(x);
}
}
int query(int x){
int ret = 0;
while(x > 0){
ret = max(ret ,c[x]);
x -= lowbit(x);
}
return ret;
}
}t[N];
int main(){
int T;scanf("%d", &T);
while(T--){
int m, n;
scanf("%d%d", &n, &m);
for(int i = 0; i < n; i++){
scanf("%d%d", &a[i], &b[i]);
h[i] = a[i]; h[i+n] = b[i];
}
sort(h, h + 2 * n);
nn = unique(h, h + 2 * n) - h;
for(int i = 0; i < n; i++){
a[i] = lower_bound(h, h + nn, a[i]) - h + 1;
b[i] = lower_bound(h, h + nn, b[i]) - h + 1;
}
int ma = 1;
memset(t, 0, sizeof(t));
for(int i = 0; i < n; i++){
for(int j = m; j >= 0; j--){
int x1 = t[j].query(a[i] - 1) + 1;
if(x1 > ma) ma = x1;
t[j].update(a[i], x1);
if(j > 0){
int x2 = t[j-1].query(b[i] - 1) + 1;
if(x2 > ma) ma = x2;
t[j].update(b[i], x2);
}
}
}
printf("%d\n", ma);
}
return 0;
}