题目链接:点击查看

题目大意:给出一个字符串,求出最长的回文子串

题目分析:如果用以往的方法求,不可避免的都需要枚举所有子串,时间复杂度就已经到达了O(n),而后缀数组可以通过O(n)预处理后得到所有子串的信息,我们可以利用这一点,将该字符串通过一个不同的符号,将其反转后的字符串拼接到后面,跑完后缀数组后求一下最长公共前缀就好了,这里有两种方法,第一种是利用height数组比较相邻两个sa数组,如果相邻的两个sa分别位于前缀和后缀,那么该height可以做出相应的贡献,不过需要注意的是需要排除掉非对称子串位置的影响,举个很简单的例子,如果不排除掉这个影响,跑zzzdanndzzz得出的答案应该是zzzd,这里只需要加上一句判断sa[i]+sa[i-1]+height[i]==len是否成立就好了,还有一种方法比较简单,但细节很多,就是直接用RMQ对height数组处理一下,然后直接遍历一遍原串,对于每个位置作为回文串的中心位置,向对称的位置求height数组就能知道以当前位置为中心的最大子串了,对于每个位置 i:

  1. 若当前需要求出偶数的回文串,则对应的位置为 n - i ,此时的长度为 2 * height[i],起点为 i - height[i]
  2. 若当前需要求出奇数的回文串,则对应的位置为 n - i - 1 ,此时的长度为 2 * height[i] - 1,起点为 i - height[i] + 1

实时记录一下起点和长度就好了,虽然用马拉车也能类似的做,但是需要分奇偶,十分麻烦,或许用二分+哈希可以替代后缀数组做这一类问题,关于RMQ,有一些细节与一般的RMQ不太一样,具体实现看代码吧:

代码:

RMQ:

#include<iostream>
#include<cstdio>
#include<string>
#include<ctime>
#include<cstring>
#include<algorithm>
#include<stack>
#include<queue>
#include<map>
#include<set>
#include<sstream>
using namespace std;typedef long long LL;const int inf=0x3f3f3f3f;const int N=2e3+100;char str[N];int sa[N]; //SA数组,表示将S的n个后缀从小到大排序后把排好序的
//的后缀的开头位置顺次放入SA中
int t1[N],t2[N],c[N];int rk[N],height[N],len;int s[N];int st[N][25];void build_sa(int s[],int n,int m)//n为添加0后的总长
{int i,j,p,*x=t1,*y=t2;for(i=0;i<m;i++) c[i]=0;for(i=0;i<n;i++) c[x[i]=s[i]]++;for(i=1;i<m;i++) c[i]+=c[i-1];for(i=n-1;i>=0;i--) sa[--c[x[i]]]=i;for(j=1;j<=n;j<<=1) {p=0;for(i=n-j;i<n;i++) y[p++]=i;for(i=0;i<n;i++) if(sa[i]>=j) y[p++]=sa[i]-j;for(i=0;i<m;i++) c[i]=0;for(i=0;i<n;i++) c[x[y[i]]]++;for(i=1;i<m;i++) c[i]+=c[i-1];for(i=n-1;i>=0;i--) sa[--c[x[y[i]]]]=y[i];swap(x,y);p=1,x[sa[0]]=0;for(i=1;i<n;i++) x[sa[i]]=y[sa[i-1]]==y[sa[i]]&&y[sa[i-1]+j]==y[sa[i]+j]?p-1:p++;if(p>=n) break;m=p;}
}void get_height(int s[],int n)//n为添加0后的总长
{int i,j,k=0;for(i=0;i<=n;i++)rk[sa[i]]=i;for(i=0;i<n;i++) {if(k) k--;j=sa[rk[i]-1];while(s[i+k]==s[j+k]) k++;height[rk[i]]=k;}
}void solve(int base=128)
{build_sa(s,len+1,base);get_height(s,len);
}void ST_build()
{for(int i=1;i<=len;i++)st[i][0]=height[i];for(int i=1;i<=log2(len);i++)for(int j=1;j+(1<<i)-1<=len;j++)st[j][i]=min(st[j][i-1],st[j+(1<<i-1)][i-1]);
}int ST_query(int a,int b)
{int l=rk[a],r=rk[b];if(l>r)swap(l,r);l++;int k=log2(r-l+1);return min(st[l][k],st[r-(1<<k)+1][k]);
}int main()
{
//  freopen("input.txt","r",stdin);
//  ios::sync_with_stdio(false);scanf("%s",str);int lena=strlen(str);len=0;for(int i=0;str[i];i++)s[len++]=str[i];s[len++]=1;for(int i=lena-1;i>=0;i--)s[len++]=str[i];s[len]=0;solve();ST_build();int start,max_len=-inf;for(int i=0;i<lena;i++){int temp=ST_query(i,len-i-1);//回文串长度为奇数 if(2*temp-1>max_len){max_len=2*temp-1;start=i-temp+1;}temp=ST_query(i,len-i);//回文串长度为偶数 if(2*temp>max_len){max_len=2*temp;start=i-temp;}}for(int i=start;i<start+max_len;i++)putchar(str[i]);putchar('\n');return 0;
}

URAL - 1297 Palindrome(后缀数组+RMQ)相关推荐

  1. 【uva10829-求形如UVU的串的个数】后缀数组+rmq or 直接for水过

    题意:UVU形式的串的个数,V的长度规定,U要一样,位置不同即为不同字串 https://uva.onlinejudge.org/index.php?option=com_onlinejudge&am ...

  2. URAL 题目1297. Palindrome(后缀数组+RMQ求最长回文子串)

    1297. Palindrome Time limit: 1.0 second Memory limit: 64 MB The "U.S. Robots" HQ has just ...

  3. hdu 2459 (后缀数组+RMQ)

    题意:让你求一个串中连续重复次数最多的串(不重叠),如果重复的次数一样多的话就输出字典序小的那一串. 分析:有一道比这个简单一些的题spoj 687, 假设一个长度为l的子串重复出现两次,那么它必然会 ...

  4. HDU - 4552 怪盗基德的挑战书(后缀数组+RMQ/KMP+dp)

    题目链接:点击查看 题目大意:给出一个字符串,统计每个前缀在字符串中出现的次数之和 题目分析:可以直接先用后缀数组跑出来height,再用RMQ跑出来任意两个后缀的height,我们可以将题意转换为求 ...

  5. hdu 5008 Boring String Problem(后缀数组+rmq)

    题目链接:hdu 5008 Boring String Problem 题意: 给你一个字符串,有q个询问,每次询问该字符串所有的子串中字典序第k小的是哪个串,输出位置,如果有多个位置,输出最靠左的那 ...

  6. HDU - 6194 string string string(后缀数组+RMQ+容斥)

    题目链接:点击查看 题目大意:给出一个字符串和一个数字 k,问字符串中出现次数恰好等于 k 次的字串有多少个 题目分析:在跑完后缀数组后,我们可以用sa数组求解,具体做法是枚举起点,找长度为 k 的s ...

  7. HDU 6194 string string string 后缀数组 + RMQ(线段树)

    传送门:HDU6194 题意:问给定字符串中有多少种出现k次的子串. 思路:首先想到后缀数组经典问题,求出现不少于k次的子串的最大长度,类似的这题肯定就是在height数组上搞事情啦. 将height ...

  8. Ural 1297 Palindrome(后缀数组+最长回文子串)

    https://vjudge.net/problem/URAL-1297 题意: 求最长回文子串. 思路: 先将整个字符串反过来写在原字符串后面,中间需要用特殊字符隔开,那么只需要某两个后缀的最长公共 ...

  9. POJ - 3693 Maximum repetition substring(后缀数组+RMQ)

    题目链接:点击查看 题目大意:给出一个字符串,求出字符串中 重复次数最多的连续重复子串 ,如果有多个答案,输出字典序最小的 题目分析:又是一个模板题,这里放一个大佬的博客,讲的很清楚: https:/ ...

最新文章

  1. 采样算法哪家强?一个针对主流采样算法的比较
  2. python ATM购物程序
  3. Django(四)数据库
  4. python面试题之Python 的特点和优点是什么
  5. 论剑乌镇:历届互联网大会热词盘点
  6. Java事务处理全解析(三)——丑陋的案例
  7. con排插与单片机相连_单片机与电路绘图自学手册
  8. 第六届信息类研究生学术论坛参赛有感
  9. 【原创】php ssh2 远程秘钥登录华三防火墙F5030
  10. WiFi基本概念(八)(信道估计 L-STF,L-LTF,Pilots)
  11. 四种“不使用第三方变量就可以交换两个变量值”的方法
  12. ios开发者中心,证书,APPID,配置文件
  13. 结构体指针和结构体指针变量的区别
  14. 让你怀疑人生的“良心”软件大集锦,360可能是最“惊喜”!
  15. 方维直播源码:*****我是如何搭建网络视频直播平台的*****
  16. 本田思域HATCHBACK哪款值得买? CVT潮酷控性价比最高
  17. Hive ,Hsql行转列、列转行实现
  18. 使用python实现地理位置查询经纬度
  19. js获取当前时间、获取未来多少天的时间、获取星期、获取某一天的年月方法
  20. linux下 cuda8,9,10 对应的cudnn 下载网盘链接分享

热门文章

  1. Oracle vs MySQL
  2. getView的解析流程
  3. AbstractAutowireCapableBeanFactory 类对容器生成的Bean 添加后置处理器
  4. vue指令-循环指令
  5. 阿里云OSS存储之SDK的使用
  6. 数据库-优化-索引-索引的优化注意事项
  7. webflux系列--源码解析二
  8. 网络套接字(Network socket)
  9. cJSON_译(C中的超轻量级JSON解析器)
  10. (轉貼) Jolt 2007得獎名單 (News) (.NET)