Advanced Guide to Algorithm Competition---0x14 (Hash) Palindrome

Topic

Insert picture description here

answer

  1. The meaning of the question is to ask for the longest back text string in a string. You can use the Manacher template question or the string hash to do it. Here we mainly talk about the string hash method.
  1. For a palindrome string with the midpoint as the dividing line, the strings on both sides are the same, then we can use the hash value to judge whether the strings on both sides are the same. For example, abcdcba, we can count the hash directly, and count the hash backward. , And then enumerate each point, take this point as the length of the dividing point, and compare whether its hash is the same
  1. The palindrome string is divided into even and odd. For odd numbers, there is a midpoint, and for even numbers, there is no. For convenience, we can make the palindrome strings into odd numbers, just add an unoccurring character in the middle of each letter.

Code 1

#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<algorithm>

using namespace std;
typedef unsigned long long ULL;
const int N = 2e6 + 10;
const int P = 131;

char s[N];
ULL hl[N], hr[N], p[N];

ULL get(ULL h[], int l, int r) {
    
    
    return h[r] - h[l - 1] * p[r - l + 1];
}

int main() {
    
    

    int t = 0;
    while (cin >> s + 1, strcmp(s + 1, "END")) {
    
    
        int n = strlen(s + 1);
        n *= 2;
        for (int i = n; i > 0; i -= 2) {
    
    
            s[i] = s[i / 2];
            s[i - 1] = '#';
        }

        p[0] = 1;
        for (int i = 1, j = n; i <= n; i++, j--) {
    
    
            hl[i] = hl[i - 1] * P + s[i];
            hr[i] = hr[i - 1] * P + s[j];
            p[i] = p[i - 1] * P;
        }

        int res = 0;
        for (int i = 1; i <= n; i++) {
    
    
            int l = 0, r = min(i - 1, n - i);
            while (l < r) {
    
    
                int mid = (l + r + 1) >> 1;
                if (get(hl, i - mid, i - 1) != get(hr, n - (i + mid) + 1, n - (i + 1) + 1)) r = mid - 1;
                else l = mid;
            }
            if (s[i - l] == '#') res = max(res, l);
            else res = max(res, l + 1);
        }
        cout << "Case " << ++t << ": " << res << endl;
    }

    return 0;
}


Code 2 (Manacher)

#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<algorithm>
#include<vector>
#include<queue>

using namespace std;
const int N = 1e6 + 10;

char a[2 * N];
int p[2 * N];

int Manacher(string c) {
    
    
    int l = 0;
    a[l++] = '$', a[l++] = '#';
    for (int i = 0; i < c.size(); i++) {
    
    
        a[l++] = c[i];
        a[l++] = '#';
    }
    a[l] = '0';
    int mx = 0;
    int id = 0;
    int maxlen = -1;
    for (int i = 1; i < l - 1; i++) {
    
    
        p[i] = mx > i ? min(p[2 * id - i], mx - i) : 1;
        while (a[i - p[i]] == a[i + p[i]]) {
    
    
            p[i]++;
        }
        if (i + p[i] > mx) {
    
    
            mx = i + p[i];
            id = i;
        }
        if (p[i] > maxlen) {
    
    
            maxlen = p[i] - 1;
        }
    }
    return maxlen;
}

int main() {
    
    

    string s;
    int t = 0;
    while (cin >> s && s != "END") {
    
    
        cout << "Case " << ++t << ": " << Manacher(s) << endl;
    }

    return 0;
}


Guess you like

Origin blog.csdn.net/qq_44791484/article/details/113854151