杭电2018多校第五场(2018 Multi-University Training Contest 5) 1008.Hills And Valleys (HDU6357) -非严格递增子序列(最长非下降子序列)-字符串+dp-区间翻转l,r找最长非递减子序列,好题哇

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\n",ans,L,R);
96     }
97 }

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

猜你喜欢

转载自www.cnblogs.com/ZERO-/p/9493597.html
今日推荐