题目链接:hdu 5406 CRB and Apple
将树按照高度从大到小排序,高度相同的美味值小的放前面。然后高度值就没有用了,等于说对得到的美味值序列求两个不相交的LIS,使得长度和尽量长。对序列元素离散化后,dp[i][j]表示说两个序列的终止位置分别为i,j的最大长度。从左向右考虑每个美味值,复杂度o(n)。对于一个值c,更新dp数组,枚举第一维状态i,复杂度o(n)。dp[i][c] = dp[c][i] = max(dp[i][j] | j < c),o(n),但是这里可以用树状数组或是其他数据结构,优化到log(n)。注意不能边枚举变修改,会对答案造成影响。
#include <cstdio> #include <cstring> #include <algorithm> using namespace std; #define lowbit(x) ((x)&(-x)) const int maxn = 1005; struct Item { int h, d; bool operator < (const Item& u) const { return h > u.h || (h == u.h && d < u.d); } }P[maxn]; int N, M, idx[maxn], top, fenw[maxn][maxn]; void add (int* f, int x, int w) { while (x < maxn) { f[x] = max(f[x], w); x += lowbit(x); } } int find(int* f, int x) { int ret = 0; while (x) { ret = max(ret, f[x]); x -= lowbit(x); } return ret; } void init () { scanf("%d", &N); memset(fenw, 0, sizeof(fenw)); for (int i = 0; i < N; i++) { scanf("%d%d", &P[i].h, &P[i].d); idx[i] = P[i].d; } sort(P, P + N); top = 1; sort(idx, idx + N); for (int i = 1; i < N; i++) { if (idx[i] == idx[top-1]) continue; idx[top++] = idx[i]; } for (int i = 0; i < N; i++) P[i].d = lower_bound(idx, idx + top, P[i].d) - idx + 1; } int solve () { int ans = 0, tmp[maxn]; for (int i = 0; i < N; i++) { int v = P[i].d; for (int j = 0; j <= top; j++) tmp[j] = find(fenw[j], v + 1) + 1; for (int j = 0; j <= top; j++) { ans = max(ans, tmp[j]); add(fenw[j], v + 1, tmp[j]); add(fenw[v], j + 1, tmp[j]); } } return ans; } int main () { int cas; scanf("%d", &cas); while (cas--) { init (); printf("%d\n", solve()); } return 0; }