UVA-257
本题意义是给你一堆字符串,将其中具有两个长度超过3的回文串的字符串输出
要求这两个回文字符串不能完全覆盖,但是可以重合,而且这两个回文字符串不能相同。
由于要求长度大于3而且可以重合,我们只要求每个长度为3/4的回文串就可以了,当某个位置存在长度>=3的回文串,如果串长为奇数,那么就取3,否则取4,然后把遍历指针i往后挪一位(去掉覆盖的情况),之后用hash判重就可以了。
比如AAAA
我们找到第一个AAA 然后把i++,这样就避免了AAAA覆盖AAA的情况
因为我们只考虑长度为3/4的回文串,所以只考虑这一种覆盖情况即可。
求某个位置为中心回文串的长度时,可以用manacher算法来计算出每个位置的回文半径。
UVA-257代码
#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<string.h>
#include<sstream>
#include<map>
using namespace std;
typedef unsigned long long ull;
const int maxn=110010;
char s[maxn];
map<ull,int> mp;
char Ma[maxn*2];
int Mp[maxn*2];
string line;
string str;
ull hash_[maxn],xp[maxn];
void init()
{xp[0]=1;for(int i=1;i<maxn;i++)xp[i]=xp[i-1]*13331;return ;
}
void make_hash(char str[])
{int len=strlen(str);hash_[len]=0;for(int i=len-1;i>=0;i--){hash_[i]=hash_[i+1]*13331+str[i]-'A'+1;}return ;
}
ull Get_hash(int i,int L)
{return hash_[i]-hash_[i+L]*xp[L];
}
void Manacher(char s[],int len)
{int l=0;Ma[l++]='$';Ma[l++]='#';for(int i=0; i<len; i++){Ma[l++]=s[i];Ma[l++]='#';}Ma[l]=0;int mx=0,id=0;for(int i=0; i<l; i++){Mp[i]=mx>i?min(Mp[2*id-i],mx-i):1;while(Ma[i+Mp[i]]==Ma[i-Mp[i]])Mp[i]++;if(i+Mp[i]>mx){mx=i+Mp[i];id=i;}}
}
int main()
{int ans=0;init();while(scanf("%s",s)!=EOF){mp.clear();int len=strlen(s);make_hash(s);Manacher(s,len);//manacher之后,Mp[i]-1为i位置的回文半径int cnt=0;for(int i=0;i<2*len+2;i++){if(Mp[i]-1>=3){if(Mp[i]%2==1)//回文串为偶数,取长度四的回文串{int st=(i-1)/2-2;int le=4;ull tmp=Get_hash(st,le);mp[tmp]++;}else//回文串为奇数,取长度三的回文串{int st=i/2-2;int le=3;ull tmp=Get_hash(st,le);mp[tmp]++;}i++;//当前位置存在大于三的回文串,避免覆盖后移一位。}}if(mp.size()>=2) printf("%s\n",s);}return 0;
}