zoukankan      html  css  js  c++  java
  • 【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个什么。
    这样方便优化。

  • 相关阅读:
    从开心网的奴隶安抚与折磨想到员工积极性与人力成本的问题
    悲剧的做网站的,我们都没有认真的前行
    如何做生意
    Android Market中产品图标设计原则
    控制UpdataPanel中的GridView模板列控件同步刷新
    DataTable筛选
    IE6,7,8,FF兼容总结
    DevPress Grid 设置行样式
    SQL分组查询
    DevexPress checkedit 多选解决方案(原创)
  • 原文地址:https://www.cnblogs.com/hiweibolu/p/6714903.html
Copyright © 2011-2022 走看看