zoukankan      html  css  js  c++  java
  • bzoj4758: [Usaco2017 Jan]Subsequence Reversal(区间dp)

    4758: [Usaco2017 Jan]Subsequence Reversal

    Time Limit: 10 Sec  Memory Limit: 128 MB
    Submit: 76  Solved: 52
    [Submit][Status][Discuss]

    Description

    Farmer John is arranging his NN cows in a line to take a photo (1≤N≤50). The height of the iith co
    w in sequence is a(i), and Farmer John thinks it would make for an aesthetically pleasing photo if t
    he cow lineup has a large increasing subsequence of cows by height.To recall, a subsequence is a sub
    set a(i1),a(i2),…,a(ik)) of elements from the cow sequence, found at some series of indices i1<i2<
    …<ik, We say the subsequence is increasing if a(i1)≤a(i2)≤…≤a(ik).FJ would like there to be a l
    ong increasing subsequence within his ordering of the cows. In order to ensure this, he allows himse
    lf initially to choose any subsequence and reverse its elements.
     
    For example, if we had the list
     
    1 6 2 3 4 3 5 3 4
    We can reverse the chosen elements
     
    1 6 2 3 4 3 5 3 4
      ^         ^ ^ ^
    to get
     
    1 4 2 3 4 3 3 5 6
      ^         ^ ^ ^
    Observe how the subsequence being reversed ends up using the same indices as it initially occupied, 
    leaving the other elements unchanged.Please find the maximum possible length of an increasing subseq
    uence, given that you can choose to reverse an arbitrary subsequence once.
    给定一个长度为N的序列,允许翻转一个子序列,求最长不下降子序列长度。n和数字都<=50
     

     

    Input

    The first line of input contains N. The remaining N lines contain a(1)…a(N),
    each an integer in the range 1…50.
     

     

    Output

    Output the number of elements that can possibly form a longest increasing subsequence 
    after reversing the contents of at most one subsequence.
     

     

    Sample Input

    9
    1
    2
    3
    9
    5
    6
    8
    7
    4

    Sample Output

    9

    HINT

     

    Source

    Platinum

    /*
    感觉这道题没完全懂
    开始设状态毫无思路,只知道可能很多维......
    想到可能是道区间dp,emm那就考虑一段区间[l,r]怎么维护里面交换那些数呢?
    发现可以用值域这个东西把数给框住。又,反转区间肯定是越靠右的反转到越靠左位置。
    那么由小区间推大区间时,只需要判断端点处包不包括在这一次的交换中即可。 
    所以可dp[i][j][L][R]为区间[i,j]里面min(ak) >= L, max(ak) <= R时,反转一次的最长不下降子序列。
    转移见代码。 
    */
    #include<bits/stdc++.h>
    
    #define N 51
    
    using namespace std;
    int n,a[N],ans;
    int dp[N][N][N][N];
    
    inline int read()
    {
        int x=0,f=1;char c=getchar();
        while(c>'9'||c<'0'){if(c=='-')f=-1;c=getchar();}
        while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
        return x*f;
    }
    
    int main()
    {
      n=read();
      for(int i=1; i <= n; ++i) a[i]=read(),dp[i][i][a[i]][a[i]]=1;
      
      for(int len=2; len <= n; ++len) for(int i=1; i+len-1 <= n; ++i)//当前区间 
          {
                   int j=i+len-1;
                for(int l=1; l <= 50; ++l) for(int L=1; L+l-1 <= 50; ++L)//当前值域 
                {
                      int R=L+l-1;
                      ans=dp[i][j][L][R];
                      ans=max(ans,max(dp[i+1][j][L][R],dp[i][j-1][L][R]));
                      ans=max(ans,max(dp[i][j][L+1][R],dp[i][j][L][R-1]));
                      dp[i][j][L][R]=ans;
                      //copy小区间的答案 
                      dp[i][j][min(L,a[i])][R]=max(dp[i][j][min(L,a[i])][R],dp[i+1][j][L][R]+(a[i] <= L));
                      dp[i][j][L][max(R,a[j])]=max(dp[i][j][L][max(R,a[j])],dp[i][j-1][L][R]+(a[j] >= R));
                      dp[i][j][min(L,a[i])][max(R,a[j])]=max(dp[i][j][min(L,a[i])][max(R,a[j])],dp[i+1][j-1][L][R]+(a[j] >= R)+(a[i] <= L));
                      //a[i]与a[j]不交换 
                      dp[i][j][min(L,a[j])][R]=max(dp[i][j][min(L,a[j])][R],dp[i+1][j-1][L][R]+(a[j] <= L));  
                      dp[i][j][L][max(R,a[i])]=max(dp[i][j][L][max(R,a[i])],dp[i+1][j-1][L][R]+(a[i] >= R));
                      dp[i][j][min(L,a[j])][max(R,a[i])]=max(dp[i][j][min(L,a[j])][max(R,a[i])],dp[i+1][j-1][L][R]+(a[i] >= R)+(a[j] <= L));
                       //a[i]与a[j]交换 
                }
          }
      cout<<dp[1][n][1][50]<<endl;
      return 0;
    }
  • 相关阅读:
    javascript 字符串与正则
    微信小程序 实现三级联动-省市区
    VUE图片懒加载-vue lazyload插件的简单使用
    移动端使用mint-ui loadmore实现下拉刷新上拉显示更多
    vue-cli创建的项目中引入第三方库报错 'caller', 'calle', and 'arguments' properties .....报错问题
    js判断两个数组是否相等
    234回文链表
    剑指 Offer 22. 链表中倒数第k个节点
    返回倒数第 k 个节点
    leetcode 179.最大数
  • 原文地址:https://www.cnblogs.com/L-Memory/p/9884053.html
Copyright © 2011-2022 走看看