分析:我們可以用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;
}