51nod 1753 相似子串

来源:互联网 发布:通利琴行淘宝店铺 编辑:程序博客网 时间:2024/06/07 21:57

51nod 1753 相似子串

原题链接:
https://www.51nod.com/onlineJudge/questionCode.html#!problemId=1753

很少写字符串hash的题目。这算是第一个啦

对字符单独考虑。

考虑字符串的hash

定义A[k][i]

A[k][i]=[s[i]=k]

对于一个01s ,定义它的hash值为:

h(s)=i=1|s|s[i]bi  mod P,P

为了避免冲突。多次hash

那么对于等价的字符形成的01串的hash值是可以直接相加的

因为一个字符只可能属于一个A[k][]

hash值其实是一个b进制数.所以不会出现某一位数字超过1

那么如果有s1,s2有一位不同时:
hash(s1)hash(s2)=Pk

直接查询即可。

#include <algorithm>#include <string.h>#include <stdio.h>#include <cmath>#define MAXN 300005using namespace std;typedef long long LL;const char ll='0'-1;const char rr='9'+1;struct Io{    char A[MAXN];    char *Pb=A,*Pe=A;    void Io_fread()    {        Pb=A;        Pe=A+fread(A,1,MAXN,stdin);    }    void s_read(char *s)    {        if(Pb==Pe)Io_fread();        if(Pb==Pe)return ;        while(*Pb=='\n'||*Pb=='\r'||*Pb==' ')        {            Pb++;            if(Pb==Pe)            {                Io_fread();                if(Pb==Pe)return ;            }        }        while(*Pb!='\n'&&*Pb!='\r')        {            *s=*Pb;            s++;            Pb++;            if(Pb==Pe)            {                Io_fread();                if(Pb==Pe)                {                    *s=0;                    return;                }            }        }        *s=0;    }    char c_read()//读取一个字符 不读 空格换行    {        if(Pb==Pe)Io_fread();        if(Pb==Pe)return -1;        while(*Pb=='\n'||*Pb=='\r'||*Pb==' ')        {            Pb++;            if(Pb==Pe)            {                Io_fread();                if(Pb==Pe)return -1;            }        }        return *(Pb++);    }    int read()    {        int tmp=0;        if(Pb==Pe)Io_fread();        if(Pb==Pe)return -1;        while(*Pb=='\n'||*Pb=='\r'||*Pb==' ')        {            Pb++;            if(Pb==Pe)            {                Io_fread();                if(Pb==Pe)return -1;            }        }       while(*Pb>ll&&*Pb<rr)       {           tmp=tmp*10+(*Pb-'0');           Pb++;           if(Pb==Pe)           {               Io_fread();               if(Pe==Pb)return tmp;           }       }        return tmp;    }}I;const int P1=998244353;const int P2=985661441;const int P3=1e8+7;const LL base=1e9+7;struct HasH{    int k1,k2,k3;    HasH(int k1,int k2,int k3):k1(k1),k2(k2),k3(k3){}    HasH()    {        k1=k2=k3=0;    }    bool operator ==(const HasH&a)const    {        return k1==a.k1&&k2==a.k2&&k3==a.k3;    }    HasH operator +(const HasH &a)const    {        return HasH((k1+a.k1)%P1,(k2+a.k2)%P2,(k3+a.k3)%P3);    }    HasH operator -(const HasH &a)const    {        return HasH((k1-a.k1+P1)%P1,(k2-a.k2+P2)%P2,(k3-a.k3+P3)%P3);    }}H[26][MAXN];struct node{    int k,d;    node(int k,int d):k(k),d(d){};    node()    {        *this=node(0,-1);    }    bool operator <(const node &a)const    {        if(k!=a.k)return k<a.k;        return d<a.d;    }    bool operator ==(const node &a)const    {        return d==a.d;    }}B[3][MAXN];int Pow(int a,int b,int mod){    LL tmp=1;    while(b)    {        if(b&1)            tmp=tmp*a%mod;        a=(LL)a*a%mod;        b>>=1;    }    return (int)tmp;}int Iv[3][MAXN];int po[3][MAXN];void init(){    po[0][0]=po[1][0]=po[2][0]=1;    for(int i=0;i<MAXN;i++)    {        B[0][i]=node(po[0][i],i);        B[1][i]=node(po[1][i],i);        B[2][i]=node(po[2][i],i);        Iv[0][i]=Pow(po[0][i],P1-2,P1);        Iv[1][i]=Pow(po[1][i],P2-2,P2);        Iv[2][i]=Pow(po[2][i],P3-2,P3);        if(i+1<MAXN)po[0][i+1]=base*po[0][i]%P1;        if(i+1<MAXN)po[1][i+1]=base*po[1][i]%P2;        if(i+1<MAXN)po[2][i+1]=base*po[2][i]%P3;    }    sort(B[0],B[0]+MAXN);    sort(B[1],B[1]+MAXN);    sort(B[2],B[2]+MAXN);}struct Bf{    int A[26];    void clear()    {        for(int i=0;i<26;i++)A[i]=i;    }    Bf()    {        clear();    }    int find(int a)    {        if(a==A[a])return a;        return A[a]=find(A[a]);    }    void merg(int a,int b)    {        a=find(a);        b=find(b);        A[a]=b;    }}F;char s[MAXN];bool vis[26];HasH used[2][26];int camp(int b){    int k1=(P1+used[0][b].k1-used[1][b].k1)%P1;    int k2=(P2+used[0][b].k2-used[1][b].k2)%P2;    int k3=(P3+used[0][b].k3-used[1][b].k3)%P3;    int d1=(int)(lower_bound(B[0],B[0]+MAXN,node(k1,-1))-B[0]);    if(d1<MAXN&&B[0][d1].k==k1)    {        for(int j=d1;j<MAXN&&B[0][j].k==B[0][d1].k;j++)        {            int d=(int)(lower_bound(B[1],B[1]+MAXN,node(k2,B[0][j].d))-B[1]);            if(d>=MAXN||B[1][d].k!=k2||!(B[0][j]==B[1][d]))continue;            d=(int)(lower_bound(B[2],B[2]+MAXN,node(k3,B[0][j].d))-B[2]);            if(d>=MAXN||B[2][d].k!=k3||!(B[0][j]==B[2][d]))continue;            return 1;        }    }    k1=(P1-k1)%P1;    k2=(P2-k2)%P2;    k3=(P3-k3)%P3;    d1=(int)(lower_bound(B[0],B[0]+MAXN,node(k1,-1))-B[0]);    if(d1<MAXN&&B[0][d1].k==k1)    {        for(int j=d1;j<MAXN&&B[0][j].k==B[0][d1].k;j++)        {            int d=(int)(lower_bound(B[1],B[1]+MAXN,node(k2,B[0][j].d))-B[1]);            if(d>=MAXN||B[1][d].k!=k2||!(B[0][j]==B[1][d]))continue;            d=(int)(lower_bound(B[2],B[2]+MAXN,node(k3,B[0][j].d))-B[2]);            if(d>=MAXN||B[2][d].k!=k3||!(B[0][j]==B[2][d]))continue;            return 1;        }    }    return 3;}int main (){    init();    I.s_read(s+1);    for(int i=0;i<26;i++)    {        for(int j=1;s[j];j++)        {            if(s[j]-'a'==i)                H[i][j]=HasH(po[0][j],po[1][j],po[2][j]);            H[i][j]=H[i][j-1]+H[i][j];        }    }    int t,k,l1,l2,r1,r2;    char a,b;    t=I.read();    while(t--)    {        F.clear();        memset(vis,0,sizeof vis);        for(int i=0;i<26;i++)used[0][i]=used[1][i]=HasH(0,0,0);        k=I.read();        l1=I.read();        r1=I.read();        l2=I.read();        r2=I.read();        for(int i=0;i<k;i++)        {            a=I.c_read();            b=I.c_read();            F.merg(a-'a',b-'a');        }        if(r1-l1!=r2-l2)        {            printf("NO\n");            continue;        }        for(int i=0;i<26;i++)        {            int u=F.find(i);            used[0][u]=used[0][u]+H[i][r1]-H[i][l1-1];            used[1][u]=used[1][u]+H[i][r2]-H[i][l2-1];        }        int flag=0;        for(int u=0;u<26;u++)        {            int i=F.find(u);            if(vis[i])continue;            vis[i]=true;            LL I1=Iv[0][l1-1];            LL I2=Iv[1][l1-1];            LL I3=Iv[2][l1-1];            used[0][i].k1=I1*used[0][i].k1%P1;            used[0][i].k2=I2*used[0][i].k2%P2;            used[0][i].k3=I3*used[0][i].k3%P3;            I1=Iv[0][l2-1];            I2=Iv[1][l2-1];            I3=Iv[2][l2-1];            used[1][i].k1=I1*used[1][i].k1%P1;            used[1][i].k2=I2*used[1][i].k2%P2;            used[1][i].k3=I3*used[1][i].k3%P3;            if(used[0][i]==used[1][i])continue;            flag+=camp(i);            if(flag>2)break;        }        if(flag<3)            printf("YES\n");        else            printf("NO\n");    }}