【JZOJ4762】【NOIP2016提高A组模拟9.7】千帆渡

2023-05-31,,

题目描述

输入

输出

样例输入

5

1 4 2 5 1

4

1 1 2 4

样例输出

2

1 4

数据范围

解法

设f[i][j]表示 i个蓝色帆船中,选择了 j个红色帆船作为结尾的最大答案。

那么:

f[i][j]=max(f[i−1][k]+1)(k<j,a[k]<b[j],a[i]=b[j])

f[i][j]=f[i−1][j](a[i]!=b[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\n",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个什么。

这样方便优化。

【JZOJ4762】【NOIP2016提高A组模拟9.7】千帆渡的相关教程结束。

《【JZOJ4762】【NOIP2016提高A组模拟9.7】千帆渡.doc》

下载本文的Word格式文档,以方便收藏与打印。