洛谷【P1439】【模板】最长公共上升子序列
浅谈\(DP\):https://www.cnblogs.com/AKMer/p/10437525.html
题目传送门:https://www.luogu.org/problemnew/show/P1439
设\(f[i][j]\)表示在\(a\)序列中\([1,i]\)和\(b\)序列的\([1,j]\)的最长公共子序列。
那么\(f[i][j]=max\){\(f[i-1][j],f[i][j-1],f[i-1][j-1]+(a[i]==b[j])\)}
初始都为\(0\),\(f[n][n]\)即为答案。
时间复杂度:\(O(n^2)\)
空间复杂度:\(O(n^2)\)
代码如下:
#include <cstdio>
#include <algorithm>
using namespace std;
const int maxn=1e3+5;
int n;
int f[maxn][maxn];
int a[maxn],b[maxn];
int read() {
int x=0,f=1;char ch=getchar();
for(;ch<'0'||ch>'9';ch=getchar())if(ch=='-')f=-1;
for(;ch>='0'&&ch<='9';ch=getchar())x=x*10+ch-'0';
return x*f;
}
int main() {
n=read();
for(int i=1;i<=n;i++)
a[i]=read();
for(int i=1;i<=n;i++)
b[i]=read();
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++) {
f[i][j]=max(f[i][j],f[i-1][j-1]+(a[i]==b[j]));
f[i][j]=max(f[i][j],max(f[i][j-1],f[i-1][j]));
}
printf("%d\n",f[n][n]);
return 0;
}
由于问题给出的是一个排列,所以我们可以把第二个序列变成相应的在第一个序列中的位置,那么这个时候最长公共子序列就变成了第二个序列的最长上升子序列了,这一个子序列会保证都在两个序列里出现过。
时间复杂度:\(O(nlogn)\)
空间复杂度:\(O(n)\)
代码如下:
#include <cstdio>
#include <algorithm>
using namespace std;
#define low(i) ((i)&(-(i)))
const int maxn=1e5+5;
int n;
int pos[maxn];
int read() {
int x=0,f=1;char ch=getchar();
for(;ch<'0'||ch>'9';ch=getchar())if(ch=='-')f=-1;
for(;ch>='0'&&ch<='9';ch=getchar())x=x*10+ch-'0';
return x*f;
}
struct tree_array {
int c[maxn];
void add(int pos,int v) {
for(int i=pos;i<=n;i+=low(i))
c[i]=max(c[i],v);
}
int query(int pos) {
int res=0;
for(int i=pos;i;i-=low(i))
res=max(res,c[i]);
return res;
}
}T;
int main() {
n=read();
for(int i=1;i<=n;i++) {
int x=read();
pos[x]=i;
}
for(int i=1;i<=n;i++) {
int x=read();x=pos[x];
int f=T.query(x-1)+1;
T.add(x,f);
}
printf("%d\n",T.query(n));
return 0;
}