天天看點

【UVA 257 Palinwords】Manacher+Hash

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=;
char s[maxn];
map<ull,int> mp;
char Ma[maxn*];
int Mp[maxn*];
string line;
string str;
ull hash_[maxn],xp[maxn];
void init()
{
    xp[]=;
    for(int i=;i<maxn;i++)
        xp[i]=xp[i-]*;
    return ;
}
void make_hash(char str[])
{
    int len=strlen(str);
    hash_[len]=;
    for(int i=len-;i>=;i--)
    {
        hash_[i]=hash_[i+]*+str[i]-'A'+;
    }
    return ;
}
ull Get_hash(int i,int L)
{
    return hash_[i]-hash_[i+L]*xp[L];
}
void Manacher(char s[],int len)
{
    int l=;
    Ma[l++]='$';
        Ma[l++]='#';
        for(int i=; i<len; i++)
        {
            Ma[l++]=s[i];
            Ma[l++]='#';
        }
        Ma[l]=;
        int mx=,id=;
        for(int i=; i<l; i++)
        {
            Mp[i]=mx>i?min(Mp[*id-i],mx-i):;
           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=;
    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=;
        for(int i=;i<*len+;i++)
        {
            if(Mp[i]->=)
            {
                if(Mp[i]%==)//回文串為偶數,取長度四的回文串
                {
                    int st=(i-)/-;
                    int le=;
                    ull tmp=Get_hash(st,le);
                    mp[tmp]++;
                }
                else//回文串為奇數,取長度三的回文串
                {
                    int st=i/-;
                    int le=;
                    ull tmp=Get_hash(st,le);
                    mp[tmp]++;
                }
                i++;//目前位置存在大于三的回文串,避免覆寫後移一位。
            }
        }
        if(mp.size()>=) printf("%s\n",s);
    }
    return ;
}