【poj2127】 Greatest Common Increasing Subsequence
http://poj.org/problem?id=2127 (题目链接)
题意
计算两个序列$a$和&b$的最长公共上升子序列。
Solution
爸爸的$n^3$算法莫名其妙RE了,不爽之下学习了一发$n^2$的。
http://www.cnblogs.com/dream-wind/archive/2012/08/25/2655641.html
$f[i][j]$表示序列$a$的前$i$位,序列$b$的前$j$位,以$b_j$结尾的最长公共上升子序列长度。
转移:$$f[i][j]=f[i-1][j](a_i!=b_j)$$
$$f[i][j]=max_{1<=k<j}f[i-1][k]+1(a_i=b_j)$$
这样直接做的话是$n^3$的,我们用前缀最大值优化一下,然后记录方案即可。
代码
// poj2127 #include<algorithm> #include<iostream> #include<cstdlib> #include<cstring> #include<cstdio> #include<cmath> #define LL long long #define inf (1ll<<60) #define Pi acos(-1.0) #define free(a) freopen(a".in","r",stdin),freopen(a".out","w",stdout); using namespace std; const int maxn=1000; int a[maxn],b[maxn],f[maxn][maxn],p[maxn][maxn],ans[maxn]; int n,m; int main() { while (scanf("%d",&n)!=EOF) { for (int i=1;i<=n;i++) scanf("%d",&a[i]); scanf("%d",&m); for (int i=1;i<=m;i++) scanf("%d",&b[i]); int sum=0,ai,aj; for (int i=1;i<=n;i++) { int mx=0,mj=0; for (int j=1;j<=m;j++) { f[i][j]=f[i-1][j]; p[i][j]=-1; if (b[j]<a[i] && f[i-1][j]>mx) mx=f[i-1][j],mj=j; else if (a[i]==b[j]) f[i][j]=mx+1,p[i][j]=mj; if (sum<f[i][j]) sum=f[i][j],ai=i,aj=j; } } printf("%d\n",sum); int tmp=sum; for (;ai;ai--) if (p[ai][aj]>-1) ans[tmp--]=b[aj],aj=p[ai][aj]; for (int i=1;i<=sum;i++) printf("%d ",ans[i]); puts(""); } return 0; }
This passage is made by MashiroSky.