【字符串哈希】Ybt_回文子串

题目大意

给你多个字符串,要你求各字符串的最长回文子串的长度。
一行一个字符串,以一行END结束。


字符串哈希。
分析题目:回文串就是串的前半部分,和后半部分倒过来完全相同的串。
我们可以分别从前往后处理,从后往前处理,得出正着和倒着的哈希值。
然后枚举回文中心,二分回文长度,比较枚举出的串的前半部分和后半部分的哈希值。


代码

#include <cstdio>
#include <cstring>
#include <iostream>
#define ull unsigned long long  //大大大大大!!自然溢出吧!!
using namespace std;
int l, r, mid, t, len, ans;
ull c[1000050], z[1000050], f[1000050];
char s[1000050];  //读入串,它比字符串快
void work() {
    
    
    memset(z, 0, sizeof(z));
    memset(f, 0, sizeof(f));
    ans = 1;  //一个字母
    for (int i = 0; i < len; ++i) z[i + 1] = z[i] * 131 + s[i];  //正着
    for (int i = len; i > 0; --i) f[i] = f[i + 1] * 131 + s[i - 1];  //反着
    for (int i = 1; i <= len; ++i) {
    
    //枚举中心
        l = 0;
        r = (len >> 1) + 1;
        while (r >= l) {
    
       //奇数长度回文
            mid = (l + r) >> 1;
            if (i - mid <= 0 || i + mid > len)
                r = mid - 1;
            else if (z[i] - z[i - mid - 1] * c[mid + 1] == f[i] - f[i + mid + 1] * c[mid + 1]) {
    
    
            //前串与后串对比
            //类似前缀和的,后减(前挪位后的值)=需取串的哈希值
                ans = max(ans, mid * 2 + 1);
                l = mid + 1;
            } else
                r = mid - 1;
        }
        l = 0;
        r = (len >> 1) + 1;
        if (z[i] - z[i - 1] * 131 == f[i + 1] - f[i + 2] * 131)
            ans = max(ans, 2);
        while (r >= l) {
    
      //偶数长度回文
            mid = (l + r) >> 1;
            if (mid == 0)
                break;
            if (i - mid + 1 <= 0 || i + mid > len)
                r = mid - 1;
            else if (z[i] - z[i - mid] * c[mid] == f[i + 1] - f[i + mid + 1] * c[mid]) {
    
    
            //前串与后串对比
                ans = max(ans, mid * 2);
                l = mid + 1;
            } else
                r = mid - 1;
        }
    }
    printf("Case %d: %d\n", t, ans);  //输出
}
int main() {
    
    
    char cc;
    c[0] = 1;
    for (int i = 1; i <= 1000000; ++i) c[i] = c[i - 1] * 131;
    cc = getchar();  //输入串
    len = 0;
    while (cc != ' ' && cc != '\n') {
    
    
        s[len] = cc;
        cc = getchar();
        ++len;
    }
    t = 1;
    while (s[0] != 'E') {
    
      //结束
        work();
        ++t;
        cc = getchar();
        len = 0;
        while (cc != ' ' && cc != '\n') {
    
    
            s[len] = cc;
            if (cc >= 'A' && cc <= 'Z')
                return 0;
            cc = getchar();
            ++len;
        }
    }
}

猜你喜欢

转载自blog.csdn.net/qq_42937087/article/details/114412844