递推方程BC的题解讲得很清楚了:
if(a[i] > a[j]) for(int k = 0; k <= j && k <= m; k++) dp[i][k][0] = max(dp[i][k][0], dp[j][k][0] + 1); if(a[i] > b[j]) for(int k = 1; k <= j && k <= m; k++) dp[i][k][0] = max(dp[i][k][0], dp[j][k][1] + 1); if(b[i] > a[j]) for(int k = 0; k <= j && k < m; k++) dp[i][k + 1][1] = max(dp[i][k + 1][1], dp[j][k][0] + 1); if(b[i] > b[j]) for(int k = 1; k <= j && k < m; k++) dp[i][k + 1][1] = max(dp[i][k + 1][1], dp[j][k][1] + 1);
但是这样会超时【其实直接递推也有过了的】
在找最大值的地方可以加优化:
对于花费同样的能量,第i个人,只需要搜索第1~i-1个人中的最大值,于是想到树状数组,可以很方便的查出1~x中的最值> <
但是树状数组如果存入的是最值,就只能越改越大;存最小值,就只能越改越小。求和无影响。
#include <iostream> #include <stdlib.h> #include <string.h> #include <stdio.h> #include <algorithm> using namespace std; #define MAXN 1010 struct BIT { int c[MAXN * 2]; int n; BIT() {} BIT(int _n) { n = _n; memset(c, 0, sizeof(c)); } int lowbit(int x) { return x & (-x); } int sum(int i) { int ret = 0; while(i) { ret = max(ret, c[i]); i -= lowbit(i); } return ret; } void add(int i, int cmp) { while(i <= n) { c[i] = max(c[i], cmp); i += lowbit(i); } } }e[MAXN]; int a[MAXN], b[MAXN], v[MAXN * 2], cnt, ans; int b_srch(int vi) { return lower_bound(v, v + cnt, vi) - v + 1; } int main() { // freopen("5125.in", "r", stdin); int t, n, m; scanf("%d", &t); while(t--) { scanf("%d%d", &n, &m); for(int i = 0; i < n; i++) { scanf("%d%d", a + i, b + i); v[2 * i] = a[i]; v[2 * i + 1] = b[i]; } sort(v, v + 2 * n); cnt = 0; for(int i = 0; i < 2 * n; i++) if(v[cnt] != v[i]) v[++cnt] = v[i]; cnt++; for(int i = 0; i < n; i++) a[i] = b_srch(a[i]), b[i] = b_srch(b[i]); ans = 0; for(int i = 0; i <= m; i++) e[i] = BIT(cnt); for(int i = 0; i < n; i++) { for(int k = 0; k <= m; k++) { int tmp = e[k].sum(a[i] - 1) + 1; e[k].add(a[i], tmp); ans = max(ans, tmp); if(k < m) { tmp = e[k + 1].sum(b[i] - 1) + 1; e[k].add(b[i], tmp); ans = max(ans, tmp); } } } printf("%d\n", ans); } return 0; }