UVA 10635 Prince and Princess

有两个长度可能是250*250的数字串,串内元素两两不同,求最长公共子串。

常规的O(n^2)解法不论是时间或空间都无法解决,办法是转化成求最长上升子序列。

假设是有串1和串2。先给串1的元素按输入顺序来一个映射,称为映射1。比如说

1 7 5 4 8 3 9 映射成 0 1 2 3 4 5 6。那么s1[7]=1,s1[9]=6。映射完成之后处理第二个字符串。

第二个字符串按映射1再来一次映射。比如 1 4 3 5 6 2 8 9 映射成,0 3 5 2 4 6 -1 -1,其中-1说明串2的该元素不在串1中出现,必然不可能算入最长公共子串中,于是对于-1的元素选择删掉,得到一个新的序列:0 3 5 2 4 6。这个新序列的意义是:串2的元素按串1元素的位置映射出的序列。那么这个新序列的最长上升子序列就是解。求最长上升子序列有一个利用二分的O(nlogn)解法,可以自行搜索。

代码:

#include <iostream>
#include <bits/stdc++.h>
using namespace std;

#define ll long long
#define mst(a,b) memset(a,b,sizeof(a))
#define rep(i,a,b) for(ll i=(a);i<(b);++i)
#define scf(n) scanf("%d", &(n));
#define lb lower_bound
const double eps = 1e-8, PI = acos(-1.0f);
const int inf = 0x3f3f3f3f, maxN = 250 + 5;
int N, P, Q, T;
int s1[maxN * maxN], s2[maxN * maxN], dp[maxN * maxN];


int main() {
#ifndef ONLINE_JUDGE
    freopen("data.in", "r", stdin);
#endif
    scf(T);
    rep(cas, 1, T + 1) {
        scanf("%d%d%d", &N, &P, &Q);
        ++P; ++Q;
        int t;
        mst(s1, -1);
        mst(s2, -1);
        rep(i, 0, P) {
            scf(t);
            s1[t] = i;
        }
        int cnt = 0;
        rep(i, 0, Q) {
            scf(t);
            if (s1[t] != -1)
                s2[cnt++] = s1[t];
        }

        mst(dp, inf);
        rep(i, 0, cnt) {
            *lb(dp, dp + cnt, s2[i]) = s2[i];
        }
        printf("Case %lld: %ld\n", cas, lb(dp, dp + cnt, inf) - dp);
    }
    return 0;
}

 

posted @ 2018-05-24 16:42  gaawing  阅读(180)  评论(0编辑  收藏  举报