zoukankan      html  css  js  c++  java
  • 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
    ",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;
    }
    
    哈哈哈哈哈哈哈哈哈哈
  • 相关阅读:
    e552. 取Applet的参数
    e551. 精简的Applet
    e558. 在Applet中多图片交互显示
    e1087. try/catch语句
    e1086. if/else语句
    e1087. 用For循环做数组的遍历
    e1084. 捕获错误和异常
    Zookeeper 应用程序
    Zookeeper API
    Java并发编程:volatile关键字解析
  • 原文地址:https://www.cnblogs.com/LZA119/p/13910100.html
Copyright © 2011-2022 走看看