CodeForces 1326D2【前缀数组next[ ]】

Prefix-Suffix Palindrome (Hard version)

题意:

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

思路:

  1. 我们找到最大的 p p ,使得 s [ 0 ] = s [ l e n 1 ] , s [ 1 ] = s [ l e n 2 ] , . . . , s [ p ] = s [ l e n 1 p ] s[0]=s[len-1], s[1]=s[len-2], ..., s[p]=s[len-1-p]
  2. s s 去掉第一步找到的 s [ 0 , p ] s[0, p] s [ l e n 1 p , l e n 1 ] s[len-1-p, len-1] ,记剩下的中间的子串为 s u b sub . 我们接下来的任务是找串 s u b sub 的最长前缀回文,或者最长后缀回文。
  3. 我们知道KMP的前缀数组: n e x t [ i ] next[ i ] 表示 s u b [ 0 , i 1 ] sub[0, i-1] 最大相同前后缀的长度。所以利用这一点我们可以求 s u b + + s u b sub+*+sub' n e x t next 数组, n e x t [ l e n ] next[len] 即为最长前缀回文的长度。
  • 至于为什么中间要加一个 * ,是因为 n e x t [   ] next[ \ ] 数组是前后缀可以交叉的最大相同前后缀的长度,如果中间不隔开,那么可能会造成得到的最长前缀回文是非法的。

样例:uwwuw
在这里插入图片描述

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

int Next[maxN];

void GetNext(string t, int len)
{
    int i = 0, j = -1;
    Next[0] = -1;
    while(i < len)
    {
        if(j == -1 || t[i] == t[j])
        {
            ++i; ++ j;
            if(t[i] != t[j])
                Next[i] = j;
            else
                Next[i] = Next[j];
        } else j = Next[j];
    }
}

int main()
{
    int t;
    while(cin >> t)
    {
        while(t -- )
        {
            string str, L, R, ans1, ans2;
            cin >> str;
            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 lenLR = R.length(), lenMid = len - lenLR * 2;
            string _sub = str.substr(lenLR, lenMid), sub = _sub;
            reverse(_sub.begin(), _sub.end());
            lenMid = lenMid << 1 | 1;
            GetNext(sub + '#' + _sub, lenMid);
            ans1 = L + sub.substr(0, Next[lenMid]) + R;
            GetNext(_sub + '#' + sub, lenMid);
            ans2 = L + _sub.substr(0, Next[lenMid]) + R;
            if(ans1.length() > ans2.length())
                cout << ans1 << endl;
            else
                cout << ans2 << endl;
        }
    }
    return 0;
}
发布了273 篇原创文章 · 获赞 76 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/weixin_44049850/article/details/104987428