题意求A、B两个序列的LCS。(A、B所含的元素分别是各不相同的)
两个序列的长度最大是250*250,朴素的LCS的时间复杂度为O(nm),因此会超时。
我们考虑这样一个操作。
对于A={1,7,5,4,8,3,9},B={1,4,3,5,6,2,8,9}
对于B中的每一个数,我们都找到其在A中出现的位置。(*没出现标为0)(因为这样不会给LIS带来贡献)
则新的B数组={1,4,6,3,0,0,5,7}
这么做的理由是:随着原来B的下标的增加,如果A中相应的数出现的位置也是这样增加的话,那么相同的数在A、B中都是在出现时间上是有序的。
我们把这些在A、B中出现时间是有序的数都抽出来,自然是二者的CS,至于LCS,它相当于新的B数组的LIS。
用一个hash实现求新的B数组。
求LIS有nlogn的方法。
如此降低了时间复杂度,利用的是元素不重复出现的这个优秀的性质。
#include <cstdio> #include <cstring> #include <algorithm> using namespace std; const int maxn = 250 * 250 + 5, inf = 1e9; int kase, n, p, q; int num[maxn], a[maxn], g[maxn]; int solve() { scanf("%d%d%d", &n, &p, &q); memset(num, 0, sizeof num); for (int i = 1; i <= p + 1; i++) { int x; scanf("%d", &x); num[x] = i; } n = 0; for (int i = 1; i <= q + 1; i++) { int x; scanf("%d", &x); if (num[x]) a[++n] = num[x]; } // for (int i = 1; i <= q + 1; i++) // printf("%d ", a[i]); for (int i = 1; i <= n; i++) g[i] = inf; int ans = 0; for (int i = 1; i <= n; i++) { int k = lower_bound(g + 1, g + 1 + i, a[i]) - g; ans = max(ans, k); g[k] = a[i]; } return ans; } int main() { // freopen("uva10635.in","r",stdin); scanf("%d", &kase); for (int i = 1; i <= kase; i++) { int ans = solve(); printf("Case %d: %d ", i, ans); } return 0; }