题目链接:

题意:给定一个只含字母的字符串,求在字符串末尾添加尽量少的字符使得字符串为回文串。

思路:因为只能从末尾添加字符,所以其实求的是最长的后缀回文串。那么添加的字符为除了这个原串的最长后缀回文串之外的其他字符。于是问题就转变成了求字符串的最长后缀回文串,对于后缀数组求回文串子串的做法,将整个字符串反过来写在原字符串后面,中间用一个特殊的字符隔开。这样就把问题变为了求这个新的字符串的某两个后缀的最长公共前缀。奇数长度和偶数长度的分开做。对于求奇数长度,假设现在枚举的位置为i,那么对应在反过来的串的位置为2*len-i。[len为输入字符串的长度,字符串的下标从0开始],求i和2*len-i的最长公共前缀,如果长度等于len-i那么就说话后缀i是回文后缀。 同理偶数长度的位置是i和2*len-i+1。关于求任意两个后缀的最长公共前缀可以用预处理+RMQ的做法。总的复杂度为O(nlogn)

#define _CRT_SECURE_NO_DEPRECATE
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<string>
#include<queue>
#include<vector>
#include<time.h>
#include<cmath>
#include<set>
using namespace std;
typedef long long int LL;
const int MAXN = * + ;
int wa[MAXN], wb[MAXN], wv[MAXN], WS[MAXN];
int cmp(int *r, int a, int b, int l)
{
return r[a] == r[b] && r[a + l] == r[b + l];
}
void da(int *r, int *sa, int n, int m)
{
int i, j, p, *x = wa, *y = wb, *t;
for (i = ; i < m; i++) WS[i] = ;
for (i = ; i < n; i++) WS[x[i] = r[i]]++;
for (i = ; i < m; i++) WS[i] += WS[i - ];
for (i = n - ; i >= ; i--) sa[--WS[x[i]]] = i;
for (j = , p = ; p < n; j *= , m = p)
{
for (p = , i = n - j; i < n; i++) y[p++] = i;
for (i = ; i < n; i++) if (sa[i] >= j) y[p++] = sa[i] - j;
for (i = ; i < n; i++) wv[i] = x[y[i]];
for (i = ; i < m; i++) WS[i] = ;
for (i = ; i < n; i++) WS[wv[i]]++;
for (i = ; i < m; i++) WS[i] += WS[i - ];
for (i = n - ; i >= ; i--) sa[--WS[wv[i]]] = y[i];
for (t = x, x = y, y = t, p = , x[sa[]] = , i = ; i < n; i++)
x[sa[i]] = cmp(y, sa[i - ], sa[i], j) ? p - : p++;
}
return;
}
int Rank[MAXN], height[MAXN], sa[MAXN];
void calheight(int *r, int *sa, int n){
int i, j, k = ;
for (i = ; i <= n; i++) { Rank[sa[i]] = i; }
for (i = ; i < n; height[Rank[i++]] = k){
for (k ? k-- : , j = sa[Rank[i] - ]; r[i + k] == r[j + k]; k++);
}
return;
}
int RMQ[MAXN], mm[MAXN], best[][MAXN];
void initRMQ(int n){
int i, j, a, b;
for (mm[] = -, i = ; i <= n; i++)
mm[i] = ((i&(i - )) == ) ? mm[i - ] + : mm[i - ];
for (i = ; i <= n; i++) best[][i] = i;
for (i = ; i <= mm[n]; i++)
for (j = ; j <= n + - ( << i); j++)
{
a = best[i - ][j];
b = best[i - ][j + ( << (i - ))];
if (RMQ[a]<RMQ[b]) best[i][j] = a;
else best[i][j] = b;
}
return;
}
int askRMQ(int a, int b){
int t;
t = mm[b - a + ]; b -= ( << t) - ;
a = best[t][a]; b = best[t][b];
return RMQ[a]<RMQ[b] ? a : b;
}
int lcp(int a, int b){
int t;
a = Rank[a]; b = Rank[b];
if (a>b) { t = a; a = b; b = t; }
return(height[askRMQ(a + , b)]);
}
char str[MAXN];
int r[MAXN], len, lenstr;
void solve(){
int plr = ;
for (int i = ; i < lenstr; i++){ //奇长度回文
int idx = * lenstr - i;
if (idx<len&&lcp(i, idx) >= lenstr - i){
plr = max(plr, (lenstr - i) * - );
}
}
for (int i = ; i < lenstr; i++){ //偶长度回文
int idx = * lenstr - i + ;
if (idx<len&&lcp(i, idx) >= lenstr - i){
plr = max(plr, (lenstr - i) * );
}
}
printf("%s", str);
for (int i = lenstr - - plr; i >= ; i--){
printf("%c", str[i]);
}
printf("\n");
}
int main(){
//#ifdef kirito
// freopen("in.txt", "r", stdin);
// freopen("out.txt", "w", stdout);
//#endif
// int start = clock();
while (~scanf("%s", str)){
lenstr = strlen(str); len = lenstr;
for (int i = ; i < lenstr; i++){
r[i] = str[i];
}
r[len++] = ;
for (int i = lenstr - ; i >= ; i--){
r[len++] = str[i];
}
r[len] = ;
da(r, sa, len + , );
calheight(r, sa, len);
for (int i = ; i <= len; i++){ RMQ[i] = height[i]; }
initRMQ(len);
solve();
}
//#ifdef LOCAL_TIME
// cout << "[Finished in " << clock() - start << " ms]" << endl;
//#endif
return ;
}

思路二:本题也可以用KMP的做法,由于只能在末尾添加字符所以可以用反过来的串和原串进行匹配,看看最后能匹配多次就是最长后缀回文的长度了。对于求回文串不仅仅可以用后缀数组和KMP,HASH,manacher,回文树都是可行的办法,不过这题还是KMP比较容易写而且运行时间明显比后缀数组快

#define _CRT_SECURE_NO_DEPRECATE
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<string>
#include<queue>
#include<vector>
#include<time.h>
#include<cmath>
#include<set>
using namespace std;
typedef long long int LL;
const int MAXN = * + ;
char str[MAXN], restr[MAXN];
int Next[MAXN], len;
void getNext(char *s, int len){
int i = , j = -;
memset(Next, , sizeof(Next));
Next[] = -;
while (i<len){
if (j == - || s[i] == s[j]){
i++; j++;
Next[i] = j;
}
else{
j = Next[j];
}
}
}
int KMP(char *str, char *restr, int len){
int j = ;
for (int i = ; i<len; i++){
while (j != - && restr[j] != str[i]){
j = Next[j];
}
if (restr[j] == str[i]){
j++;
}
if (j == -){
j = ;
}
}
return j;
}
int main(){
//#ifdef kirito
// freopen("in.txt", "r", stdin);
// freopen("out.txt", "w", stdout);
//#endif
// int start = clock();
while (scanf("%s", str) != EOF){
len = strlen(str);
for (int i = len - ; i >= ; i--){
restr[len - i - ] = str[i];
}
getNext(restr, len);
printf("%s", str);
for (int i = KMP(str, restr, len) ; i<len; i++){
printf("%c", restr[i]);
}
printf("\n");
}
//#ifdef LOCAL_TIME
// cout << "[Finished in " << clock() - start << " ms]" << endl;
//#endif
return ;
}

UVA 11475 后缀数组/KMP的更多相关文章

  1. hdu5442(2015长春赛区网络赛1006)后缀数组+KMP /最小表示法?

    题意:给定一个由小写字母组成的长度为 n 的字符串,首尾相连,可以从任意一个字符开始,顺时针或逆时针取这个串(长度为 n),求一个字典序最大的字符串的开始字符位置和顺时针或逆时针.如果有多个字典序最大 ...

  2. POJ 3450 后缀数组/KMP

    题目链接:http://poj.org/problem?id=3450 题意:给定n个字符串,求n个字符串的最长公共子串,无解输出IDENTITY LOST,否则最长的公共子串.有多组解时输出字典序最 ...

  3. hdu 5769 Substring 后缀数组 + KMP

    http://acm.hdu.edu.cn/showproblem.php?pid=5769 题意:在S串中找出X串出现的不同子串的数目? 其中1 <= |S| < $10^5$ 官方题解 ...

  4. UVA - 10298 后缀数组(仅观赏)

    题意:求最小循环节 \(KMP\)可以20ms通过,而\(da\)实现的后缀数组并无法在3000ms内通过 听说要用\(dc3\)才勉强卡过,这里仅列出\(da\)实现 #include<ios ...

  5. poj 2406 Power Strings (后缀数组 || KMP)

    Power Strings Time Limit: 3000MS   Memory Limit: 65536K Total Submissions: 28859   Accepted: 12045 D ...

  6. POJ3080 POJ3450Corporate Identity(广义后缀自动机||后缀数组||KMP)

    Beside other services, ACM helps companies to clearly state their “corporate identity”, which includ ...

  7. BZOJ 3796 后缀数组+KMP

    思路: 写得我头脑发蒙,,, 旁边还有俩唱歌的 抓狂 (感谢lh大爷查错) 首先 1.w是s1的子串 2.w是s2的子串 这两步很好办啊~ 后缀数组一下O(n)就可以搞 重点是 这个:3.s3不是w的 ...

  8. BZOJ3796 Mushroom追妹纸(二分答案+后缀数组+KMP)

    求出一个串使得这个串是\(s1,s2\)的子串.串中不包含\(s3\). 如果没有这个\(s3\)就可以二分答案,然后height小于二分值分一组.看看每组里是不是出现过\(s1,s2\)的后缀.判断 ...

  9. UVa 11107 (后缀数组 二分) Life Forms

    利用height值对后缀进行分组的方法很常用,好吧,那就先记下了. 题意: 给出n个字符串,求一个长度最大的字符串使得它在超过一半的字符串中出现. 多解的话,按字典序输出全部解. 分析: 在所有输入的 ...

随机推荐

  1. 【leetcode】Longest Consecutive Sequence(hard)☆

    Given an unsorted array of integers, find the length of the longest consecutive elements sequence. F ...

  2. 在Win7下使用sphinx-build建立开源软件文档

    最近想看看odoo的使用文档,在线看不方便,而且还没有提供离线文档下载,由于是开源项目,此项目托管在Github上,于是就有了想通过Github把文档git下来,可是git下来的文档是.rst文件,无 ...

  3. supersr--时间显示逻辑-->NSDate+NSCalendar

    一种:时间逻辑: - (NSString *)created_at{ //    从后台返回的字符串格式:Mon Aug 03 09:17:31 +0800 2014, //NSDateFormatt ...

  4. 【2016-09-16】UbuntuServer14.04或更高版本安装问题记录

    出于项目需要,我们的Qt程序需要运行在 1. Windows/Linux-X86平台(CPU为常见的桌面级CPU如G3220.I3等): 2. Windows/Linux-X86低功耗平台(CPU为I ...

  5. mongodb3.x版本用户管理方法

    db.auth() 作用:验证用户到数据库. 语法: db.auth( { user: <username>, pwd: <password>, mechanism: < ...

  6. XMPP框架下微信项目总结(1)环境配置

    xmpp介绍 xmpp基于模块开发的 无须自己写请求 (登陆,注册,获取好友列表,添加/删除好友等) ------>简介 ------------------------- ----->工 ...

  7. StoryBoard和代码结合 按比例快速兼容iPhone6/6 Plus教程

     转:http://www.cocoachina.com/ios/20141230/10800.html 编者注:根据网友们的评论,文章中的方法有很大的局限性,请谨慎使用! 现在由于苹果公司出了6和6 ...

  8. 一个TextView内显示不同颜色的文字

    String format = "<font color='#FC8262'>%s</font>:%s"; String text = String.for ...

  9. 解决git客户端MINGW32下的“Could not open a connection to your authentication agent.”

    使用git, 下载客户端后想进行和github 进行ssh 互通 出现以下情况: hadoop@deng-PC MINGW32 ~/.ssh$ ssh-add ~/.ssh/id_rsaCould n ...

  10. 【PHP Cookie&&Session】

    大部分的人都知道Cookie,但是可能不了解Session,现在对这两者进行解释. 问题的提出: 有些网站会提示用户在一定的时间之内免登陆,这是用的什么技术?答案是Cookie技术. 有些购物网站会提 ...