jzoj 5815. 【省选模拟2018.8.14】回文串 回文树+字符串hash

Description
这里写图片描述
Input
这里写图片描述
Output
这里写图片描述
Sample Input

B
newionyzz
wyxioiwen
1
1 1

Sample Output

16

Data Constraint
这里写图片描述
Hint
这里写图片描述

分析:
由于 A 串取某个后缀, B 串取某个前缀,所以可以先把 A 串反过来。然后就是同时取一段前缀,组合成一个回文串变为一段相同的公共后缀+一个在公共前缀的前面的回文串。这样我们可以把回文树建出来,记录下每个以位置 A i 的结尾的串有多少个,这个显然可以从 f a i l 转移,对于另一个串也这么做。然后给这个跑一个前缀和,就是找最长公共后缀。这个可以使用二分+字符串hash搞定。但是这题非常恶心的卡空间,好像是为了给manacher过(mdzz), 最后连回文树上的儿子都开了map,打了单hash,总算是卡过了。

代码:

#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <map>
#define LL long long

const int maxn=800007;
const int mod=233333333;

using namespace std;

char a[maxn],b[maxn];
int len1,len2,cnt,test,x,y;

struct node{
    int fail,len,sum;
    map <int,int> son;  
}t[maxn];

LL hash1[maxn],hash2[maxn],bit[maxn];
LL f[maxn],g[maxn];

void pre()
{
    for (int i=1;i<=len1;i++)
    {
        hash1[i]=(hash1[i-1]*26+(a[i]-'a'))%mod;
    }
    for (int i=1;i<=len2;i++)
    {
        for (int j=0;j<=1;j++)
        {
            hash2[i]=(hash2[i-1]*26+(b[i]-'a'))%mod;
        }
    }
}

void build_tree(char *s,int len,LL *f)
{
    for (int i=0;i<maxn;i++)
    {
        t[i].fail=0;
        t[i].len=0;
        t[i].sum=0;
        t[i].son.clear();
    }
    cnt=1;
    t[0].fail=1;
    t[0].len=0;
    t[1].fail=0;
    t[1].len=-1;
    int now=1;
    for (int i=1;i<=len;i++)
    {
        while (s[i]!=s[i-t[now].len-1]) now=t[now].fail;
        if (!t[now].son[s[i]-'a'])
        {
            cnt++;
            int k=t[now].fail;
            while (s[i]!=s[i-t[k].len-1]) k=t[k].fail;
            t[cnt].fail=t[k].son[s[i]-'a'];
            t[now].son[s[i]-'a']=cnt;
            t[cnt].len=t[now].len+2;
            t[cnt].sum=t[t[cnt].fail].sum+1;
        }
        now=t[now].son[s[i]-'a'];
        f[i]=t[now].sum;
    }
    for (int i=1;i<=len;i++) f[i]=f[i-1]+f[i];
}

bool check(int l,int r,int x,int y)
{
    int len1=(r-l)+1,len2=(y-x)+1;
    LL h1,h2;
    h1=(hash1[r]+mod-hash1[l-1]*bit[len1]%mod)%mod;
    h2=(hash2[y]+mod-hash2[x-1]*bit[len2]%mod)%mod;
    return (h1==h2);
}

int main()
{
    freopen("palindrome.in","r",stdin);
    freopen("palindrome.out","w",stdout);
    scanf("%s",a);
    scanf("%s",a);
    scanf("%s",b);
    len1=strlen(a);
    len2=strlen(b);
    for (int i=0;i<=(len1/2)-1;i++) swap(a[i],a[len1-i-1]); 
    for (int i=len1-1;i>=0;i--) a[i+1]=a[i];
    for (int i=len2-1;i>=0;i--) b[i+1]=b[i];
    a[0]='#'; b[0]='#';
    bit[0]=1;
    for (int i=1;i<=max(len1,len2);i++)
    {
        bit[i]=(bit[i-1]*26)%mod;
    }       
    pre();
    build_tree(a,len1,f);
    build_tree(b,len2,g);   
    scanf("%d",&test);  
    for (int i=1;i<=test;i++)
    {
        scanf("%d%d",&x,&y);
        x=len1-x+1; 
        y=len2-y+1;
        int l=0,r=min(x,y),maxlen=0;
        while (l<=r)
        {
            int mid=(l+r)/2;
            if (check(x-mid+1,x,y-mid+1,y)) maxlen=mid,l=mid+1;
                                       else r=mid-1;
        }
        printf("%lld\n",f[x-1]-f[x-maxlen-1]+g[y-1]-g[y-maxlen-1]+maxlen);
    }
}

猜你喜欢

转载自blog.csdn.net/liangzihao1/article/details/81665022