JZOJ 4762. 【NOIP2016提高A组模拟9.7】千帆渡(DP)

JZOJ 4762. 【NOIP2016提高A组模拟9.7】千帆渡

题目

Description

在这里插入图片描述

Input

在这里插入图片描述

Output

在这里插入图片描述

Sample Input

5
1 4 2 5 1
4
1 1 2 4

Sample Output

2
1 4

Data Constraint

在这里插入图片描述

题解

好像挺显然地是一道动态规划题。
怎么设状态?
如果设 f [ i ] [ j ] f[i][j] f[i][j]为以 a [ i ] a[i] a[i] b [ j ] b[j] b[j]作为末尾的最大答案,这样必须保证 a [ i ] = b [ j ] a[i]=b[j] a[i]=b[j],不仅会浪费很大的空间,而且转移起来也是 O ( n 2 m 2 ) O(n^2m^2) O(n2m2)的,时间必然超限。
但如果设 f [ i ] [ j ] f[i][j] f[i][j]表示以 a [ k ] ( k ≤ i ) a[k](k≤i) a[k](ki) b [ j ] b[j] b[j]作为末尾的最大大案,这样能有一些较为便捷的转移:
1、 a [ i ] = b [ j ] a[i]=b[j] a[i]=b[j] f [ i ] [ j ] = m a x ( f [ i − 1 ] [ k ] ) ( k ≤ j f[i][j]=max(f[i-1][k])(k≤j f[i][j]=max(f[i1][k])(kj b [ k ] < b [ j ] ) b[k]<b[j]) b[k]<b[j])
2、 a [ i ] ≠ b [ j ] a[i]≠b[j] a[i]=b[j] f [ i ] [ j ] = f [ i − 1 ] [ j ] f[i][j]=f[i-1][j] f[i][j]=f[i1][j]
怎么统计方案?
在存储最大长度的同时记录下由什么位置转移得到,最后从后往前倒推求值即可。
但这样是 O ( n m 2 ) O(nm^2) O(nm2)的,还要优化。
很显然地,第一种情况的 m a x max max可以用边做边维护。
a [ i ] = b [ j ] a[i]=b[j] a[i]=b[j] f [ i ] [ j ] = m a x ( f [ i − 1 ] [ k ] ) ( k ≤ j f[i][j]=max(f[i-1][k])(k≤j f[i][j]=max(f[i1][k])(kj b [ k ] < b [ j ] ) b[k]<b[j]) b[k]<b[j])
其实也就是 f [ i ] [ j ] = m a x ( f [ i − 1 ] [ k ] ) ( k ≤ j f[i][j]=max(f[i-1][k])(k≤j f[i][j]=max(f[i1][k])(kj b [ k ] < a [ i ] ) b[k]<a[i]) b[k]<a[i])
那么就可以:
b [ j ] < a [ i ] b[j]<a[i] b[j]<a[i]时,如果 f [ i − 1 ] [ j ] > m a x f[i-1][j]>max f[i1][j]>max,则 m a x = f [ i − 1 ] [ j ] max=f[i-1][j] max=f[i1][j].
于是这题就轻松地突破了!

代码

#include<cstdio>
#include<cstring>
using namespace std;
int a[5010],b[5010],ans[5010];
int f[5010][5010],g[5010][5010],h[5010][5010];
struct
{
	int x,h;
}max[5010];
int main()
{
	int n,m,i,j,k;
	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<=m;j++)
		{
			if(a[i]!=b[j]) 
			{
				f[i][j]=f[i-1][j];
				g[i][j]=g[i-1][j];
				h[i][j]=h[i-1][j];
			}
			else 
			{
				if(max[i-1].x+1>f[i][j])
				{
					f[i][j]=max[i-1].x+1;
					g[i][j]=i-1;
					h[i][j]=max[i-1].h;
				}
			}
			if(b[j]<a[i]) 
			{
				if(f[i-1][j]>max[i-1].x)
				{
					max[i-1].x=f[i-1][j];
					max[i-1].h=j;
				}
			}
		}
	int s=0;
	for(i=1;i<=m;i++) if(f[n][i]>f[n][s]) s=i;;
	printf("%d\n",f[n][s]);
	int x=n,y=s;
	s=f[n][s];
	while(x!=0&&s>0)
	{
		ans[s]=b[y];
		int x1=x;
		x=g[x][y];
		y=h[x1][y];
		s--;
	}
	s=0;
	while(ans[s+1]!=0) printf("%d ",ans[++s]);
	return 0;
}
posted @ 2019-01-02 21:46  AnAn_119  阅读(58)  评论(0编辑  收藏  举报