UVA 11475 Extend to Palindrome(后缀数组+ST表)

【题目链接】 http://acm.hust.edu.cn/vjudge/problem/27647

【题目大意】

  给出一个字符串,要求在其后面添加最少的字符数,使得其成为一个回文串。并输出这个回文串。

【题解】

  用拼接符将原字符串倒序相接,做一遍后缀数组,查询两串相应位置的LCP就是以该点为中心的回文串长度的一半分,奇偶求出所有后缀回文串,保留最长的,则补充部分为剩下的前缀的倒置。至于查询两串的LCP我们可以在height数组建立ST表查询。

【代码】

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int N=4000010;
int n,m,Rank[N],sa[N],h[N],tmp[N],cnt[N],ans;char s[N],t[N];
void suffixarray(int n,int m){
    int i,j,k;n++;
    for(i=0;i<2*n+5;i++)Rank[i]=sa[i]=h[i]=tmp[i]=0;
    for(i=0;i<m;i++)cnt[i]=0;
    for(i=0;i<n;i++)cnt[Rank[i]=s[i]]++;
    for(i=1;i<m;i++)cnt[i]+=cnt[i-1];
    for(i=0;i<n;i++)sa[--cnt[Rank[i]]]=i;
    for(k=1;k<=n;k<<=1){
        for(i=0;i<n;i++){
            j=sa[i]-k;
            if(j<0)j+=n;
            tmp[cnt[Rank[j]]++]=j;
        }sa[tmp[cnt[0]=0]]=j=0;
        for(i=1;i<n;i++){
            if(Rank[tmp[i]]!=Rank[tmp[i-1]]||Rank[tmp[i]+k]!=Rank[tmp[i-1]+k])cnt[++j]=i;
            sa[tmp[i]]=j;
        }memcpy(Rank,sa,n*sizeof(int));
        memcpy(sa,tmp,n*sizeof(int));
        if(j>=n-1)break;
    }for(j=Rank[h[i=k=0]=0];i<n-1;i++,k++)
    while(~k&&s[i]!=s[sa[j-1]+k])h[j]=k--,j=Rank[sa[j]+1];
}
int f[N][30],lg2[N];
void rmq_init(int n){
    for(int i=2;i<=n;i++)lg2[i]=lg2[i/2]+1;
    for(int i=1;i<=n;i++)f[i][0]=h[i];
    for(int j=1;(1<<j)<=n;j++)
    for(int i=1;i+(1<<j)-1<=n;i++)
        f[i][j]=min(f[i][j-1],f[i+(1<<(j-1))][j-1]);
}
int rmq_min(int l,int r){
    if(l>r)swap(l,r);l++;
      int k=lg2[r-l+1];
      return min(f[l][k],f[r-(1<<k)+1][k]);
}
void init(){
    int i,j;
    for(i=0;t[i];i++)s[i]=t[i];s[n=i]=‘#‘;
    for(j=i-1,++i;j>=0;i++,j--)s[i]=t[j];
    s[m=i]=0;
}
int main(){
    while(~scanf("%s",t)){
        init();
        suffixarray(m,128);
        rmq_init(m);
        int ans=0,pos=m+1;
        for(int i=0;i<n;i++){
            int k=rmq_min(Rank[i],Rank[m-1-i]);
            if(2*k-1>ans&&i+k==n)ans=2*k-1,pos=i-k+1;
            k=rmq_min(Rank[i],Rank[m-i]);
            if(2*k>ans&&i+k==n)ans=2*k,pos=i-k;
        }for(int i=0;i<n;i++)printf("%c",s[i]);
        for(int i=pos-1;i>=0;i--)printf("%c",s[i]);
        puts("");
    }return 0;
}

  

时间: 2024-10-07 07:24:00

UVA 11475 Extend to Palindrome(后缀数组+ST表)的相关文章

POJ 3693 Maximum repetition substring(后缀数组+ST表)

[题目链接] poj.org/problem?id=3693 [题目大意] 求一个串重复次数最多的连续重复子串并输出,要求字典序最小. [题解] 考虑错位匹配,设重复部分长度为l,记s[i]和s[i+l]前缀匹配得到的最长长度为r, 枚举所有的l和i,得到r,那么答案就是r/l+1的最大值. 计算任意后缀的最长公共前缀可以利用后缀数组+ST表来解决, 两个后缀的最长公共前缀就是他们名次之间的h数组的最小值. 显然,枚举i和l的复杂度达到了O(n2),是没有办法完成统计的, 我们发现每个区段只会存

SPOJ 687 Repeats(后缀数组+ST表)

[题目链接] http://www.spoj.com/problems/REPEATS/en/ [题目大意] 求重复次数最多的连续重复子串的长度. [题解] 考虑错位匹配,设重复部分长度为l,记s[i]和s[i+l]前缀匹配得到的最长长度为r,枚举所有的l和i,得到r,那么答案就是r/l+1的最大值.计算任意后缀的最长公共前缀可以利用后缀数组+ST表来解决,两个后缀的最长公共前缀就是他们名次之间的h数组的最小值. 显然,枚举i和l的复杂度达到了O(n2),是没有办法完成统计的,我们发现每个区段只

[LuoguP4094] [HEOI2016] [TJOI2016]字符串(二分答案+后缀数组+ST表+主席树)

[LuoguP4094] [HEOI2016] [TJOI2016]字符串(二分答案+后缀数组+ST表+主席树) 题面 给出一个长度为\(n\)的字符串\(s\),以及\(m\)组询问.每个询问是一个四元组\((a,b,c,d)\),问\(s[a,b]\)的所有子串和字符串\(s[c,d]\)的最长公共前缀长度的最大值. \(n,m \leq 10^5\) 分析 显然答案有单调性.首先我们二分答案\(mid\),考虑如何判定. 如果mid这个答案可行,那么一定存在一个后缀x,它的开头在\([a,

UVA 12338:Anti-Rhyme Pairs(后缀数组+ST表)

[题目链接] click [题目大意] 给出一些字符串,询问查询任意两个字符串的最长公共前缀 [题解] 将字符串拼接,对拼接的字符串做后缀数组,对于查询的两个字符串, 只要在height数组上查询区间最小值即可. 特别注意多组数据时候对字符串结尾的处理,很久没写容易忽视导致wa. [代码] #include <cstdio> #include <cstring> #include <algorithm> using namespace std; const int N=

URAL 1297 Palindrome(后缀数组+ST表)

[题目链接] http://acm.timus.ru/problem.aspx?num=1297 [题目大意] 求最长回文子串,并输出这个串. [题解] 我们将原串倒置得到一个新的串,加一个拼接符将新串拼在原串的后面, 那么枚举对称的中心点, 在两个串在组合成的串的对应位置的后缀的最长公共前缀 就是该点像两边扩展的最长回文子串的一半长度. 那么如何求任意两个后缀的最长公共前缀呢,考虑后缀数组的h数组和rank数组, 我们可以发现,两个后缀的最长公共前缀就是他们名次之间的h数组的最小值. 对h数组

UVA 11475 Extend to Palindrome KMP

题目链接:https://vjudge.net/problem/UVA-11475 题意: 给你一个串S 你可以在结尾补充任意数量字母,问最少数量使得新串是回文串 题解: KMP 将S串倒置跑KMP #include<bits/stdc++.h> using namespace std; #pragma comment(linker, "/STACK:102400000,102400000") #define ls i<<1 #define rs ls | 1

UVa 11475 - Extend to Palindrome

題目:給你一個字符串,在後面拼接一部分使得它變成回文串,使得串最短.輸出這個回文串. 分析:KMP,dp.這裡利用KMP算法將串和它的轉置匹配,看結束時匹配的長度就可以. 因為串比较長.使用KMP比较合適,KMP原理請参照AC自動機總結. 說明:╮(╯▽╰)╭. #include <string.h> #include <stdio.h> #include <stdlib.h> char strA[100001]; char strB[100001]; int next

BZOJ 2119: 股市的预测 [后缀数组 ST表]

2119: 股市的预测 Time Limit: 10 Sec  Memory Limit: 259 MBSubmit: 331  Solved: 153[Submit][Status][Discuss] Description 墨墨的妈妈热爱炒股,她要求墨墨为她编写一个软件,预测某只股票未来的走势.股票折线图是研究股票的必备工具,它通过一张时间与股票的价位的函数图像清晰地展示了股票的走势情况.经过长时间的观测,墨墨发现很多股票都有如下的规律:之前的走势很可能在短时间内重现!如图可以看到这只股票A

URAL 1297 Palindrome 后缀数组

1297. Palindrome Time limit: 1.0 second Memory limit: 64 MB The "U.S. Robots" HQ has just received a rather alarming anonymous letter. It states that the agent from the competing ?Robots Unlimited? has infiltrated into "U.S. Robotics".