题意:给定一个序列,求出这个序列中最长的一个对称的序列,并且该序列对称之中还要保持左边递增右边递减。

解法:将原串进行翻转,然后求一个最长公共上升子序列,注意边界:从原串的第i位开始匹配,那么翻转过来的串就不能够匹配到[1,i-1]这个区间去,否则非法的这一段匹配结果将会是左降右增。

代码入下:

#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <algorithm>
using namespace std;int N;
int a[205];
int f[205][205];
int dp[205];/*
定义状态f[i][j]表示以a串的前i个字符b串的前j个字符且以b[j]为结尾构成的LCIS的长度
由于有了上升的限制,因此少不了考虑前一状态的最后一个值,这也是一个限制值,通过
开设一个包含有特定位截止的状态就有利于保存下这一值
*/void solve() {int Max = -1, len;
/*    二维空间写法 memset(f, 0, sizeof (f));for (int i = 1; i <= N; ++i) {len = 0;for(int j = N; j >= i; --j) {if (a[i] == a[j]) {f[i][j]    = len + 1;if (j > i) {Max = max(Max, f[i][j] * 2);} else {Max = max(Max, f[i][j] * 2 - 1);}} else {f[i][j] = f[i-1][j];if (a[i] > a[j]) { // len维护好a[i]当前能够达到的已有的长度的最大值len = max(len, f[i-1][j]);}}}}*/// 一维空间写法memset(dp, 0, sizeof (dp));for (int i = 1; i <= N; ++i) {len = 0;for (int j = N; j >= i; --j) {if (a[i] == a[j]) {dp[j] = len + 1;if (j > i) {Max = max(Max, dp[j] * 2);}else {Max = max(Max, dp[j] * 2 - 1);}} else {if (a[i] > a[j]) {len = max(len, dp[j]);}}}    } printf("%d\n", Max);
}int main() {int T;scanf("%d", &T);while (T--) {scanf("%d", &N);for (int i = 1; i <= N; ++i) {scanf("%d", a + i);}solve();}return 0;
}

附:最长公共上升子序列算法

最长公共上升子序列(LCIS)的O(n^2)算法
预备知识:动态规划的基本思想,LCS,LIS。
问题:字符串a,字符串b,求a和b的LCIS(最长公共上升子序列)。
首先我们可以看到,这个问题具有相当多的重叠子问题。于是我们想到用DP搞。DP的首要任务是什么?定义状态。
1定义状态F[i][j]表示以a串的前i个字符b串的前j个字符且以b[j]为结尾构成的LCIS的长度。
为什么是这个而不是其他的状态定义?最重要的原因是我只会这个,还有一个原因是我知道这个定义能搞到平方的算法。而我这只会这个的原因是,这个状态定义实在是太好用了。这一点我后面再说。
我们来考察一下这个这个状态。思考这个状态能转移到哪些状态似乎有些棘手,如果把思路逆转一下,考察这个状态的最优值依赖于哪些状态,就容易许多了。这个状态依赖于哪些状态呢?
首先,在a[i]!=b[j]的时候有F[i][j]=F[i-1][j]。为什么呢?因为F[i][j]是以b[j]为结尾的LCIS,如果F[i][j]>0那么就说明a[1]..a[i]中必然有一个字符a[k]等于b[j](如果F[i][j]等于0呢?那赋值与否都没有什么影响了)。因为a[k]!=a[i],那么a[i]对F[i][j]没有贡献,于是我们不考虑它照样能得出F[i][j]的最优值。所以在a[i]!=b[j]的情况下必然有F[i][j]=F[i-1][j]。这一点参考LCS的处理方法。
那如果a[i]==b[j]呢?首先,这个等于起码保证了长度为1的LCIS。然后我们还需要去找一个最长的且能让b[j]接在其末尾的LCIS。之前最长的LCIS在哪呢?首先我们要去找的F数组的第一维必然是i-1。因为i已经拿去和b[j]配对去了,不能用了。并且也不能是i-2,因为i-1必然比i-2更优。第二维呢?那就需要枚举b[1]..b[j-1]了,因为你不知道这里面哪个最长且哪个小于b[j]。这里还有一个问题,可不可能不配对呢?也就是在a[i]==b[j]的情况下,需不需要考虑F[i][j]=F[i-1][j]的决策呢?答案是不需要。因为如果b[j]不和a[i]配对,那就是和之前的a[1]..a[j-1]配对(假设F[i-1][j]>0,等于0不考虑),这样必然没有和a[i]配对优越。(为什么必然呢?因为b[j]和a[i]配对之后的转移是max(F[i-1][k])+1,而和之前的i`配对则是max(F[i`-1][k])+1。显然有F[i][j]>F[i`][j],i`>i)
于是我们得出了状态转移方程:
a[i]!=b[j]: F[i][j]=F[i-1][j]
a[i]==b[j]: F[i][j]=max(F[i-1][k])+1 1<=k<=j-1&&b[j]>b[k]
不难看到,这是一个时间复杂度为O(n^3)的DP,离平方还有一段距离。
但是,这个算法最关键的是,如果按照一个合理的递推顺序,max(F[i-1][k])的值我们可以在之前访问F[i][k]的时候通过维护更新一个max变量得到。怎么得到呢?首先递推的顺序必须是状态的第一维在外层循环,第二维在内层循环。也就是算好了F[1][len(b)]再去算F[2][1]。
如果按照这个递推顺序我们可以在每次外层循环的开始加上令一个max变量为0,然后开始内层循环。当a[i]>b[j]的时候令max=F[i-1][j]。如果循环到了a[i]==b[j]的时候,则令F[i][j]=max+1。
最后答案是F[len(a)][1]..F[len(a)][len(b)]的最大值。
参考代码:

#include<cstdio>
#include<cstring>
int f[1005][1005],a[1005],b[1005],i,j,t,n1,n2,max;
int main()
{scanf("%d",&t);while(t--){scanf("%d%d",&n1,&n2);for(i=1;i<=n1;i++) scanf("%d",&a[i]);for(i=1;i<=n2;i++) scanf("%d",&b[i]);memset(f,0,sizeof(f));for(i=1;i<=n1;i++){max=0;for(j=1;j<=n2;j++){f[i][j]=f[i-1][j];if (a[i]>b[j]&&max<f[i-1][j]) max=f[i-1][j];if (a[i]==b[j]) f[i][j]=max+1;}}max=0;for(i=1;i<=n2;i++) if (max<f[n1][i]) max=f[n1][i];printf("%d\n",max);}
}

其实还有一个很风骚的一维的算法。在此基础上压掉了一维空间(时间还是平方)。i循环到x的时候,F[i]表示原来F[x][j]。之所以可以这样,是因为如果a[i]!=b[j],因为F[x][j]=F[x-1][j]值不变,F[x]不用改变,沿用过去的就好了,和这个比较维护更新得到的max值依然是我们要的。而a[i]==b[j]的时候,就改变F[x]的值好了。具体结合代码理解。
参考代码:

#include<cstdio>
#include<cstring>
int f[1005],a[1005],b[1005],i,j,t,n1,n2,max;
int main()
{scanf("%d",&t);while(t--){scanf("%d%d",&n1,&n2);for(i=1;i<=n1;i++) scanf("%d",&a[i]);for(i=1;i<=n2;i++) scanf("%d",&b[i]);memset(f,0,sizeof(f));for(i=1;i<=n1;i++){max=0;for(j=1;j<=n2;j++){if (a[i]>b[j]&&max<f[j]) max=f[j];if (a[i]==b[j]) f[j]=max+1;}}max=0;for(i=1;i<=n2;i++) if (max<f[i]) max=f[i];printf("%d\n",max);}
}

最长公共上升子序列(LCIS)的平方算法@我们都爱刘汝佳
2011-2-18

转载于:https://www.cnblogs.com/Lyush/archive/2013/03/25/2980286.html

HDU-4512 吉哥系列故事——完美队形I 最长公共上升子序列相关推荐

  1. HDU 4512 吉哥系列故事――完美队形I(最长公共上升子序列)

    吉哥系列故事--完美队形I Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 65535/32768 K (Java/Others) To ...

  2. hdu 4512 吉哥系列故事——完美队形I(最长公共上升自序加强版)

    首先要去学习最长公共上升子序列LCIS.然后是对n*n效率的算法进行优化,这里要注意的是能够求出来的序列中间能够有一个最高的.刚開始将输入的数组进行逆置,写下来发现这可能存在问题. 只是详细是什么也没 ...

  3. HDU 4513 吉哥系列故事――完美队形II(Manacher)

    题目链接:[kuangbin带你飞]专题十六 KMP & 扩展KMP & Manacher V - 吉哥系列故事――完美队形II 题意 吉哥又想出了一个新的完美队形游戏! 假设有n个人 ...

  4. HDU - 4513 吉哥系列故事——完美队形II(Manacher)

    题目链接:点击查看 题目大意:给出一个长度为n的数列,现在要求选出一段连续的数列,满足: 该数列为回文串 该数列的左半部分非严格递增 输出选取数列的最大长度 题目分析:因为是要选取连续的子串,并且还需 ...

  5. 吉哥系列故事——完美队形II(hdu4513+Manacher)

    吉哥系列故事--完美队形II Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 65535/32768 K (Java/Others) T ...

  6. HDUOJ 4513 吉哥系列故事——完美队形II

    HDUOJ 4513 吉哥系列故事--完美队形II Problem Description 吉哥又想出了一个新的完美队形游戏! 假设有n个人按顺序站在他的面前,他们的身高分别是h[1], h[2] - ...

  7. 吉哥系列故事――完美队形II(HDU-4513)

    Problem Description 吉哥又想出了一个新的完美队形游戏!  假设有n个人按顺序站在他的面前,他们的身高分别是h[1], h[2] ... h[n],吉哥希望从中挑出一些人,让这些人形 ...

  8. HDU 4502 吉哥系列故事——临时工计划(动态规划)

    吉哥系列故事--临时工计划                                                                                      T ...

  9. HDU 4507 吉哥系列故事――恨7不成妻 数位DP

    吉哥系列故事--恨7不成妻 Time Limit: 1000/500 MS (Java/Others)    Memory Limit: 65535/32768 K (Java/Others) Tot ...

  10. HDU 4535 吉哥系列故事——礼尚往来

    http://acm.hdu.edu.cn/showproblem.php?pid=4535 题目大意: 有n个妹纸没人送给吉哥一个礼物,他决定进行合理的分配,即将这些礼物送回去,就不用花钱买新礼物了 ...

最新文章

  1. MS 的SPACE很不好的说
  2. C++易于实现的有趣项目【附上完整教程】
  3. 强化学习 求解迷宫问题_使用天真强化学习的迷宫求解器
  4. 谷歌开源BoTNet | CNN与Transformer结合!Bottleneck Transformers for Visual Recognition!CNN+Transformer!
  5. MYSQL端口自动开启的问题~
  6. 用友U8对账不平,对账错误简单处理方法
  7. [集成IronPython] 使用Module扩展IronPython
  8. [论离职]走的人不少,来的人更多
  9. 【40周年系列活动】中国干细胞第十届年会(2020·贵阳)第二轮通知
  10. 无线路由器密码破解最新教程完整版
  11. Unity Asset Store——独立游戏开发者的素材插件商店
  12. 夜深人静写算法(一)- 搜索入门
  13. mac升级python版本_Mac上python如何升级?
  14. java月份下拉菜单_实现一个日期下拉菜单
  15. 供应商网店货源哪里找?直播带货靠谱货源(电商教程)
  16. 微信开发者解除绑定微信公众号的方法,亲测有效
  17. AndroidStudio音乐播放器进度条和歌曲时间的操作
  18. 53所高校研究生补贴一览表
  19. 如何让微信丢骰子永远只出“666”
  20. MySQL InnoDB如何解决幻读?

热门文章

  1. 才发现,我已经过不起新年了
  2. 【luogu P3979 遥远的国度】 题解
  3. LeetCode-2: Add Two Numbers
  4. Java 2017.11.20 杨浩宁作业
  5. deepin安装mysql记录
  6. 【转】Android 全屏方案(隐藏NavigationBar)
  7. Node.js(express) + MongoDB(mongoose) 简单开发(二)
  8. UML各种图画法总结
  9. Thinking in C++ ----第二章 对象的创建和使用
  10. ORB-SLAM2 ROS运行