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


    题目描述

    这里写图片描述

    输入

    这里写图片描述

    输出

    这里写图片描述

    样例输入

    5
    1 4 2 5 1
    4
    1 1 2 4

    样例输出

    2
    1 4

    数据范围

    这里写图片描述

    解法

    设f[i][j]表示 i个蓝色帆船中,选择了 j个红色帆船作为结尾的最大答案。
    那么:
    f[i][j]=max(f[i1][k]+1)(k<j,a[k]<b[j],a[i]=b[j])
    f[i][j]=f[i1][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
    ",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个什么。
    这样方便优化。

  • 相关阅读:
    hospital 基于反射的 在线医疗项目(三)
    hospital 基于反射的 在线医疗项目(二)
    【前端笔记】之 消息提示框
    hospital 基于反射的 在线医疗项目(-)
    【前端笔记】之一个简单好看的的下拉菜单 :select下拉框
    Dubbo和Zookeeper在Linux系统的安装
    记录一下Java String类的常用方法
    myeclipse与tomcat、jdk的安装和配置
    jQuery选择器总结
    js根据2个日期计算相差天数
  • 原文地址:https://www.cnblogs.com/hiweibolu/p/6714903.html
Copyright © 2020-2023  润新知