题目描述
输入
输出
样例输入
5
1 4 2 5 1
4
1 1 2 4
样例输出
2
1 4
数据范围
解法
设f[i][j]表示前 i个蓝色帆船中,选择了第 j个红色帆船作为结尾的最大答案。
那么:
考虑优化,从k入手:
维护h[i][j]表示在f[i][j] (a[i]=b[j])时最大的k使得满足转移条件。
h[i][j]可以从h[i-1][k]中转移过来。
代码
#include<iostream>
#include<stdio.h>
#include<string.h>
#include<math.h>
#include<algorithm>
using namespace std;
const char* fin="aP2.in";
const char* fout="aP2beta.out";
const int inf=0x7fffffff;
const int maxn=5007;
int read(){
char ch=getchar();
int x=0;
while (ch<'0' || ch>'9') ch=getchar();
while (ch>='0' && ch<='9') x=x*10+ch-'0',ch=getchar();
return x;
}
int n,m,i,j,k,l,o,ans=0,ans1,ans2;
int cans[maxn];
int a[maxn],b[maxn];
int f[maxn][maxn],g[maxn][maxn],h[maxn][maxn];
int main(){
scanf("%d",&n);
for (i=1;i<=n;i++) scanf("%d",&a[i]);
scanf("%d",&m);
for (i=1;i<=m;i++) scanf("%d",&b[i]);
for (i=1;i<=n;i++)
for (j=1;j<=n;j++){
if (a[i]==b[j]){
k=h[i][j];
if (k<j && b[k]<b[j] && f[i][j]<f[i-1][k]+1){
f[i][j]=f[i-1][k]+1;
g[i][j]=k;
if (ans<f[i][j]){
ans1=i;
ans2=j;
ans=f[i][j];
}
}
}else f[i][j]=f[i-1][j],g[i][j]=j;
if (b[j]<a[i+1]) {
if (f[i][h[i+1][j-1]]<f[i][j]) h[i+1][j]=j;
else h[i+1][j]=h[i+1][j-1];
}
else h[i+1][j]=h[i+1][j-1];
}
printf("%d
",ans);
while (ans1){
if (a[ans1]==b[ans2]){
cans[++cans[0]]=a[ans1];
}
j=ans1;
k=ans2;
ans1=j-1;
ans2=g[j][k];
}
for (i=ans;i;i--) printf("%d ",cans[i]);
return 0;
}
启发
当初把f[i][j]设成了选了第i个蓝色帆船和第j个红色帆船的最大答案。
然后使得动态规划优化困难。
不过也运用了去除冗余状态的方法,把这个O(n^3)的动态规划优化到了80分。
联系以前的启发;
事实上动态规划的第一维都可以设成前i个什么。
这样方便优化。