标签:长度 nlogn 处理 1.0 printf names stdin 利用 ESS
有两个长度可能是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]=2,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; }
标签:长度 nlogn 处理 1.0 printf names stdin 利用 ESS
原文地址:https://www.cnblogs.com/Rosebud/p/9083686.html