• HDU 6357.Hills And Valleys-字符串非严格递增子序列(LIS最长非下降子序列)+动态规划(区间翻转l,r找最长非递减子序列),好题哇 (2018 Multi-University Training Contest 5 1008)


    6357.

    Hills And Valleys

    自己感觉这是个好题,应该是经典题目,所以半路选手补了这道字符串的动态规划题目。

    题意就是给你一个串,翻转任意区间一次,求最长的非下降子序列。

    一看题面写的0Ai9 (i=1,2,,n).就知道肯定有点东西,只要这么写,肯定就是有某个神奇的操作可以解决这道题目。

    比赛的时候脑壳都要炸了也没想出来,补题的时候懂了,我可以定义一个b串为0123456789,这肯定是递增的,所以我翻转b的某个区间,然后去和a匹配,因为我把b再翻转回来,还是递增的。

    当然了,因为是非严格的递增子序列,有相等的情况,所以相等的时候判断一下,直接+1就可以了。然后枚举一下b的翻转区间就可以了。因为还要输出翻转的区间,所以在dp的时候,用个数组分别保存一下l,r端点就可以了。其他的没什么。

    感觉这种思路还是很值得思考的,不处理a,通过其他的操作间接处理a,以后写题要多想想,也写过类似思路的,通过其他的操作间接得到答案,但是一打比赛就没脑子,mdzz,为什么我这么菜༼༎ຶᴗ༎ຶ༽

    参考了其他人的题解写出来的。

    首先官方题解:

    然后别人的博客:HDU6357——Hills And Valleys

    代码:

     1 //1008-6357-非严格递增子序列(最长非下降子序列)-字符串+dp-区间翻转,r找最长非递减子序列,好题哇
     2 #include<iostream>
     3 #include<cstdio>
     4 #include<cstring>
     5 #include<algorithm>
     6 #include<bitset>
     7 #include<cassert>
     8 #include<cctype>
     9 #include<cmath>
    10 #include<cstdlib>
    11 #include<ctime>
    12 #include<deque>
    13 #include<iomanip>
    14 #include<list>
    15 #include<map>
    16 #include<queue>
    17 #include<set>
    18 #include<stack>
    19 #include<vector>
    20 using namespace std;
    21 typedef long long ll;
    22 
    23 const double PI=acos(-1.0);
    24 const double eps=1e-6;
    25 const ll mod=1e9+7;
    26 const int inf=0x3f3f3f3f;
    27 const int maxn=1e5+10;
    28 const int maxm=20+10;
    29 #define ios ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
    30 
    31 int n,a[maxn],dp[maxn][maxm],b[maxm];
    32 int ans,L,R,l,r,h;
    33 int al[maxn][maxm],ar[maxn][maxm];
    34 
    35 int solve()
    36 {
    37     for(int i=0;i<=h;i++)
    38         dp[0][i]=0;//初始化
    39     for(int i=1;i<=n;i++){//a和b匹配
    40         for(int j=1;j<=h;j++){
    41             dp[i][j]=dp[i-1][j];
    42             al[i][j]=al[i-1][j];//记录左端点
    43             ar[i][j]=ar[i-1][j];//记录右端点
    44             if(a[i]==b[j]){//如果有相等的情况,+1
    45                 dp[i][j]=dp[i-1][j]+1;
    46                 if(l==j&&!al[i][j])//如果当前的j就是b开始翻转的左端点,更新记录
    47                     al[i][j]=i;
    48                 if(r==j)//右端点
    49                     ar[i][j]=i;
    50             }
    51             if(dp[i][j-1]>dp[i][j]){//更新答案
    52                 dp[i][j]=dp[i][j-1];
    53                 al[i][j]=al[i][j-1];
    54                 ar[i][j]=ar[i][j-1];
    55             }
    56         }
    57     }
    58     return dp[n][h];
    59 }
    60 
    61 char s[maxn];
    62 
    63 int main()
    64 {
    65     int t;
    66     scanf("%d",&t);
    67     while(t--){
    68         scanf("%d%s",&n,s+1);
    69         for(int i=1;i<=n;i++)
    70             a[i]=s[i]-'0';
    71         h=0;
    72         for(int i=0;i<=9;i++)
    73             b[++h]=i;
    74         L=R=l=r=1;
    75         ans=solve();
    76         for(int i=0;i<=9;i++){
    77             for(int j=i+1;j<=9;j++){
    78                 h=0;
    79                 for(int k=0;k<=i;k++)
    80                     b[++h]=k;//翻转区间的左部分不变
    81                 l=h+1;
    82                 for(int k=j;k>=i;k--)//要翻转的区间把数字翻转
    83                     b[++h]=k;
    84                 r=h;
    85                 for(int k=j;k<=9;k++)//反转区间的右部分不变
    86                     b[++h]=k;
    87                 int tmp=solve();
    88                 if(ans<tmp&&al[n][h]&&ar[n][h]){//更新结果
    89                     ans=tmp;
    90                     L=al[n][h];
    91                     R=ar[n][h];
    92                 }
    93             }
    94         }
    95         printf("%d %d %d
    ",ans,L,R);
    96     }
    97 }

    溜了溜了,滚去补数据结构了。

  • 相关阅读:
    ORACLE字符串函数
    Ubuntu14.04安装wineqq国际版
    phonegap学习笔记
    Android Studio 1.5.1
    CodeBlocks+Qt(MinGW)配置
    Java多线程之synchronized(五)
    Java多线程之synchronized(四)
    Java多线程之synchronized(三)
    Java多线程之synchronized(二)
    Java多线程之synchronized(一)
  • 原文地址:https://www.cnblogs.com/ZERO-/p/9493597.html
Copyright © 2020-2023  润新知