标签:while log i++ div class string 转化 相交 最小覆盖
题意:求两个排列的最长公共子序列n<=1e5
解题关键:转化为LIS。
最长公共子序列 的 nlogn 的算法本质是 将该问题转化成 最长增序列(LIS),因为 LIS 可以用nlogn实现,所以求LCS的时间复杂度降低为 nlogn。
1. 转化:将LCS问题转化成LIS问题。
假设有两个序列 s1[ 1~6 ] = { a, b, c , a, d, c }, s2[ 1~7 ] = { c, a, b, e, d, a, b }。
记录s1中每个元素在s2中出现的位置, 再将位置按降序排列, 则上面的例子可表示为:
loc( a)= { 6, 2 }, loc( b ) = { 7, 3 }, loc( c ) = { 1 }, loc( d ) = { 5 }。
将s1中每个元素的位置按s1中元素的顺序排列成一个序列s3 = { 6, 2, 7, 3, 1, 6, 2, 5, 1 }。
在对s3求LIS得到的值即为求LCS的答案
2.求LIS的 nlogn 的算法:
覆盖:是序列s的几个不相交的降序列,它们包含了s中的所有元素,降序列的个数为c。
最小覆盖:c值最小的覆盖。
定理:序列s的最长增序列等于最小覆盖。
于是:求s的最长增序列转化成求s的最小覆盖。
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #include<cstdlib> 5 #include<iostream> 6 #include<cmath> 7 #include<string> 8 #define inf 0x3f3f3f3f 9 using namespace std; 10 typedef long long ll; 11 const int maxn=1005000; 12 int n; 13 inline int read(){ 14 char k=0;char ls;ls=getchar();for(;ls<‘0‘||ls>‘9‘;k=ls,ls=getchar()); 15 int x=0;for(;ls>=‘0‘&&ls<=‘9‘;ls=getchar())x=(x<<3)+(x<<1)+ls-‘0‘; 16 if(k==‘-‘)x=0-x;return x; 17 } 18 int ind[maxn]; 19 int a[maxn],b[maxn],dp[maxn],c[maxn]; 20 int main(){ 21 int t; 22 t=read(); 23 while(t--){ 24 n=read(); 25 for(int i=0;i<n;i++) a[i]=read(); 26 for(int i=0;i<n;i++) b[i]=read(),ind[b[i]]=i; 27 for(int i=0;i<n;i++) c[i]=ind[a[i]]; 28 fill(dp,dp+n,inf); 29 for(int i=0;i<n;i++){ 30 *lower_bound(dp,dp+n,c[i])=c[i]; 31 } 32 printf("%d\n",int(lower_bound(dp,dp+n,inf)-dp)); 33 } 34 return 0; 35 }
标签:while log i++ div class string 转化 相交 最小覆盖
原文地址:http://www.cnblogs.com/elpsycongroo/p/7429414.html