Codeforces D1/D2. Prefix-Suffix Palindrome (字符串hash) /詳解

D1. Prefix-Suffix Palindrome (Easy version)
D2. Prefix-Suffix Palindrome (Hard version)

題意:
對於給出的字符串,可截取其前綴和後綴,求能組成的最長迴文串。

思路:

  1. 正常來說暴力的思路是先匹配前綴pre和後綴suf,找到第一個不匹配的l和r,然後在由l開始從左向右求最長的迴文串palindrome,以及由r開始從右向左求最長的迴文串palindrome,那麼pre+palindrome+suf就是答案。
  2. 很顯然,這是一個O(n^2)時間複雜度的算法,那麼還有哪裏可以優化呢?其實關於求迴文串palindrome的地方可以優化,據D2的數據來看時間複雜度應該在O(n)或者O(nlogn),接下來先介紹字符串hash的做法。
  3. 對字符串hash不太瞭解的可以先看: Hash
  4. 首先肯定是先把匹配的前後綴長度x求出來,然後由不匹配的地方x+1開始從左向右匹配hash值求最長的迴文串palindrome,以及由n-x開始從左向右匹配hash值求最長的迴文串palindrome。
  5. 最後答案就是s[0…x]+palindrome+s[n-x+1…n]。
  6. 感興趣的話可參考一下這道題的Manacher做法:Manacher做法
  7. 如果有什麼講的不清楚的歡迎留言私信交流~

代碼:

#include<bits/stdc++.h>
#define ll long long
#define ull unsigned long long
#define inf 0x3f3f3f3f
#define mod 1000000007
#define PI acos(-1)
#define fi first
#define se second
#define lowbit(x) (x&(-x))
#define mp make_pair
#define pb push_back
#define ins insert
#define si size()
#define E exp(1.0)
#define fixed cout.setf(ios::fixed)
#define fixeds(x) setprecision(x)
#pragma GCC optimize(2)
using namespace std;
inline ll read(){ll s=0,w=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();return s*w;}
void put1(){ puts("YES") ;}void put2(){ puts("NO") ;}void put3(){ puts("-1"); }
ll qp(ll a,ll b, ll p){ll ans = 1;while(b){if(b&1){ans = (ans*a)%p;--b;}a =
(a*a)%p;b >>= 1;}return ans%p;}ll Inv(ll x,ll p){return qp(x,p-2,p);}
ll Cal(ll n,ll m,ll p){if (m>n) return 0;ll ans = 1;for(int i = 1; i <= m; ++i)
ans=ans*Inv(i,p)%p*(n-i+1)%p;return ans%p;}

const int manx=1e6+5;
const ull base=2333;
const ull pp=19260811;
const ull ppp=999998639;

ll pre[manx],suf[manx],po[manx];
char s[manx];

ull ha1(ll l,ll r){
    return (pre[r]-pre[l-1]*po[r-l+1]%ppp+ppp)%ppp;
}
ull ha2(ll l,ll r){
    return (suf[l]-suf[r+1]*po[r-l+1]%ppp+ppp)%ppp;
}
int main(){
    ll p=read();
    while(p--){
        cin>> s+1;
        ll n=strlen(s+1);
        pre[0]=0,suf[n+1]=0,po[0]=1;
        for(int i=1;i<=n;i++) po[i]=po[i-1]*base%ppp;
        for(int i=1;i<=n;i++) pre[i]=(pre[i-1]*base+s[i]-'a'+1)%ppp;
        for(int i=n;i>=1;i--) suf[i]=(suf[i+1]*base+s[i]-'a'+1)%ppp;
        ll l=0,r=0,x=0;
        while(s[x+1]==s[n-x]&&x+1<n-x) x++;
        for(int i=x+1;i<=n-x;i++)
            if(ha1(x+1,i)==ha2(x+1,i))
                if(i-x>l) l=i-x;
        for(int i=n-x;i>=x+1;i--)
            if(ha1(i,n-x)==ha2(i,n-x))
                if(n-x-i+1>r) r=n-x-i+1;
        for(int i=1;i<=x;i++) cout<<s[i];
        ll flag=max(l,r);
        if(flag==l) for(int i=x+1;i<=x+l;i++) cout<<s[i];
        else for(int i=n-x;i>=n-x-r+1;i--) cout<<s[i];
        for(int i=n-x+1;i<=n;i++) cout<<s[i];
        cout<<endl;
    }
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章