CodeForces 1326D2【Manacher】

Prefix-Suffix Palindrome (Hard version)

题意:

  • 给定一个串 s s s,找出一个回文串 t t t,使得 t t t = s . p r e f i x s.prefix s.prefix + s . s u f f i x s.suffix s.suffix,并且 t t t的长度不大于 s s s.

思路:

  • M a n a c h e r Manacher Manacher算法中 r a d i u s [ i ] radius[ i ] radius[i]数组表示以 i i i为中心回文串半径长。那么我们如何找到前缀回文串?
  • :也就是所有 r a d i u s [ i ] = = i radius[ i ] == i radius[i]==i中半径最大的那个,即 m a x ( i ) max(i) max(i). 那么 s [ 0 , r a d i u s [ i ] − 1 ] s[0, radius[i]-1] s[0,radius[i]1]就是最长的前缀回文。

#include <bits/stdc++.h>
using namespace std;
const int maxN = 2000100;

string Manacher(string s, int len)
{
    string t = "$#";
    for(int i = 0; i < len; ++ i ) t += s[i], t += '#';
    len = t.length();
    vector<int>radius(len, 0);
    int mx = 0, id = 0;
    for(int i = 1; i < len; ++ i )
    {
        radius[i] = mx > i ? min(radius[(id << 1) - i], mx - i) : 1;
        while(i + radius[i] < len && i - radius[i] >= 0 && t[i + radius[i]] == t[i - radius[i]])
            ++ radius[i];
        if(mx < i + radius[i])
        {
            mx = i + radius[i];
            id = i;
        }
    }
    int mxLen = 0;
    for(int i = 1; i < len; ++ i )
    {
        if(radius[i] == i)
            mxLen = radius[i] - 1;
    }
    return s.substr(0, mxLen);
}

int main()
{
    int t;
    while(cin >> t)
    {
        while(t -- )
        {
            string str; cin >> str;
            string L, R;
            int len = str.length();
            for(int i = 0; i < len / 2; ++ i)
                if(str[i] == str[len - 1 - i])
                    R += str[i];
                else
                    break;
            L = R; reverse(R.begin(), R.end());
            int lenL = L.length(), lenR = lenL;
            string res = str.substr(L.length(), len - lenL - lenR);
            string res1 = Manacher(res, len - lenL - lenR);
            reverse(res.begin(), res.end());
            string res2 = Manacher(res, len - lenL - lenR);
            if(res1.length() > res2.length())
                cout << L + res1 + R << endl;
            else
                cout << L + res2 + R << endl;
        }
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值