uva10635

题意求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;
}
原文地址:https://www.cnblogs.com/yohanlong/p/7757791.html