最长公共上升子序列的模板题,仿照LCS和LIS的状态定义方式,我们定义f[i][j]表示a1~ai与b1~bj构成的以bj结尾的LCIS的长度,显然答案为max{f[n][i]}.
当ai≠bj时,f[i][j]=f[i-1][j].
当ai=bj时,f[i][j]=max{f[i-1][k]+1} (b[k]<b[j])
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 inline int read() { 5 int ret=0,f=1; 6 char c=getchar(); 7 while(c<'0'||c>'9') {if(c=='-') f=-1;c=getchar();} 8 while(c<='9'&&c>='0') ret=ret*10+c-'0',c=getchar(); 9 return ret*f; 10 } 11 using namespace std; 12 int n,a[3010],b[3010],f[3010][3010]; 13 int main() { 14 n=read(); 15 for(int i=1;i<=n;i++) a[i]=read(); 16 for(int i=1;i<=n;i++) b[i]=read(); 17 a[0]=b[0]=-999999999; 18 for(int i=1;i<=n;i++) { 19 for(int j=1;j<=n;j++) { 20 if(a[i]==b[j]) { 21 for(int k=0;k<j;k++) 22 if(b[k]<a[i]) f[i][j]=max(f[i][j],f[i-1][k]+1); 23 } 24 else f[i][j]=f[i-1][j]; 25 } 26 } 27 int ans=0; 28 for(int i=0;i<=n;i++) 29 ans=max(ans,f[n][i]); 30 printf("%d",ans); 31 return 0; 32 }
时间复杂度为O(n3)。当n=3000时无法通过。
仔细思考:第二层循环当j变为j+1时,i是一个定值,也就是说bk<ai的条件是固定的。当j增加1时,k的取值范围从0≤k<j变为0≤k<j+1.而0≤k<j的部分我们已经计算过一遍,因此,我们用一个变量记录0≤k<j当中f[i-1][k]的最大值,在与新的f[i-1][k]比较,这样就能在O(1)的时间里完成转移。因此时间复杂度降为O(n2)。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 inline int read() { 5 int ret=0,f=1; 6 char c=getchar(); 7 while(c<'0'||c>'9') {if(c=='-') f=-1;c=getchar();} 8 while(c<='9'&&c>='0') ret=ret*10+c-'0',c=getchar(); 9 return ret*f; 10 } 11 using namespace std; 12 int n,a[3010],b[3010],f[3010][3010]; 13 int main() { 14 scanf("%d",&n); 15 for(int i=1;i<=n;i++) scanf("%d",&a[i]); 16 for(int i=1;i<=n;i++) scanf("%d",&b[i]); 17 a[0]=b[0]=-999999999; 18 for(int i=1;i<=n;i++) { 19 int val=0; 20 if(b[0]<a[i]) val=f[i-1][0]; 21 for(int j=1;j<=n;j++) { 22 if(a[i]==b[j]) f[i][j]=val+1; 23 else f[i][j]=f[i-1][j]; 24 if(b[j]<a[i]) val=max(val,f[i-1][j]); 25 } 26 } 27 int ans=0; 28 for(int i=0;i<=n;i++) 29 ans=max(ans,f[n][i]); 30 printf("%d",ans); 31 return 0; 32 }