无重复元素的LCS问题
n2 做法不说了。
nlogn 做法 ——
因为LCS问题求的是公共子序列,顺序不影响答案,影响答案的只是两个串的元素是否相同,所以可以交换元素位置。
首先简化一下问题,假设P1恰好为单调递增的1,2,3,...n,那么很显然答案就是P2的最长上升子序列的长度
问题是P1并非单调递增的,但我们可以假定它就是1,2,3,...,n。
也就是重新定义一下第一个串中 所有数 的顺序,定义a[x] = i,也就是 数x 是第 i 个,然后再重新弄一下第二串的顺序,最后求一遍lis。
——代码
1 #include <cstdio> 2 #include <algorithm> 3 #include <cstring> 4 5 using namespace std; 6 7 const int MAXN = 100001; 8 int n, ans; 9 int a[MAXN], b[MAXN], c[MAXN]; 10 11 inline int query(int x) 12 { 13 int ans = 0; 14 for(; x; x -= x & -x) ans = max(ans, c[x]); 15 return ans; 16 } 17 18 inline void update(int x, int d) 19 { 20 for(; x <= n; x += x & -x) c[x] = max(c[x], d); 21 } 22 23 int main() 24 { 25 int i, j, x, y; 26 scanf("%d", &n); 27 for (i = 1; i <= n; i++) scanf("%d", &x), a[x] = i; 28 for (i = 1; i <= n; i++) scanf("%d", &x), b[i] = a[x]; 29 for(i = 1; i <= n; i++) 30 { 31 y = query(b[i] - 1) + 1; 32 update(b[i], y); 33 ans = max(ans, y); 34 } 35 printf("%d", ans); 36 return 0; 37 }
还有另一种思路。也是 nlogn,而且比较好理解。(说实话,我真不理解上面的映射是怎么弄的)
原本 n2 做法是设 f[i][j] 表示 第一串的前 i 个数 和 第二串的前 j 个数 的最优答案(i 和 j 都不必须选),然后一阵乱搞。
nlogn——
可以改变状态的定义,f[i][j] 表示 第一串的前 i 个数 和 第二串的前 j 个数 的最有答案(i 不必须选,j 必须选)
这样 f[i][] 只能由 f[i - 1][] 转移过来,这样就变成了分层的DP,并且只转移到 f[i][k] (其中 b[k] == a[i]),也就是只影响一个答案。
所以先记录和 a[i] 相同的 b[j] 的位置,然后 f 数组可以变成一维,动态维护 f 数组即可。
f[i] = max(f[j]) + 1 ( 1 <= j < i && a[i] == b[j])
——代码
1 #include <cstdio> 2 #include <iostream> 3 4 using namespace std; 5 6 const int MAXN = 100001; 7 int n, ans; 8 int a[MAXN], b[MAXN], c[MAXN], p[MAXN], f[MAXN]; 9 10 inline int query(int x) 11 { 12 int ret = 0; 13 for(; x; x -= x & -x) ret = max(ret, c[x]); 14 return ret; 15 } 16 17 inline void update(int x, int d) 18 { 19 for(; x <= n; x += x & -x) c[x] = max(c[x], d); 20 } 21 22 int main() 23 { 24 int i; 25 scanf("%d", &n); 26 for(i = 1; i <= n; i++) scanf("%d", &a[i]); 27 for(i = 1; i <= n; i++) scanf("%d", &b[i]), p[b[i]] = i; 28 for(i = 1; i <= n; i++) 29 { 30 f[p[a[i]]] = query(p[a[i]] - 1) + 1; 31 update(p[a[i]], f[p[a[i]]]); 32 ans = max(ans, f[p[a[i]]]); 33 } 34 printf("%d", ans); 35 return 0; 36 }