POWEROJ 2610 判断回文串 【HASH】

题目链接【https://www.oj.swust.edu.cn/problem/show/2610】

题意:给你一个字符串,让你判断这个字符串是不是回文串,字符串的长度是1<len<1e7,内存是4096KB。

题解:首先这1e7个字符是存不下的,1e71024=9765KB>4096kB。那么怎么办?字符串哈希,先对字符串的前半部分进行哈希,然后在对字符串后半部分进行哈希,如果两部分的哈希值相同,那么这个字符串就是回文串。

BKDRH哈希,哈希公式为has=has*seed+s[i],seed为31,131,1313,这里选择131。对于后半部分has+=pow(seed,i-1)*s[i]。但是这样哈希会有漏洞,需要更近一步的完善,我们用unsigned long long 存HAS值,所以他会自动取模(2^64-1),

对于前半部分我们维护两个HAS值,分别对两个不同的素数取模,后半部分也一样。那么我们就维护这两对哈希值,只有当这两对哈希值都分别相等的时候,我们才认为这两段字符串是相等的,也就是回文串。具体看代码。

#include<bits/stdc++.h>
using namespace std;
typedef unsigned long long ULL;
const ULL modA = 1e9 + 7;
const ULL modB = 1e9 + 9;
ULL has[5], SEED = 131;
int N;
int main ()
{
    while(~scanf("%d", &N))
    {
        has[0] = has[1] = 0;
        has[2] = has[3] = 0;
        char s;
        char S[5];
        gets(S);
        for(int i = 1; i <= N / 2; i++)
        {
            s = getchar();
            ULL t = (ULL)s;
            has[0] = (has[0] * SEED + t) % modA;
            has[1] = (has[1] * SEED + t) % modB;
        }
        if(N % 2) s = getchar();
        ULL seed[3];
        seed[0] = seed[1] = seed[2] = (ULL)1;
        for(int i = 1; i <= N / 2; i++)
        {
            s = getchar();
            ULL t = (ULL)s ;
            has[2] = (has[2] + t * seed[0]) % modA;
            has[3] = (has[3] + t * seed[1]) % modB;
            seed[0] = seed[0] * SEED % modA;
            seed[1] = seed[1] * SEED % modB;
        }
        if(has[0] == has[2] && has[1] == has[3] )
            printf("YES\n");
        else
            printf("NO\n");
    }
    return 0;
}

 

posted @ 2017-03-20 20:11  _Mickey  阅读(1333)  评论(0编辑  收藏  举报