51nod 1753 相似子串

51nod 1753 相似子串

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

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

对字符单独考虑。

考虑字符串的 hash

定义 A[k][i]

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

对于一个 01 s ,定义它的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 300005

using 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");
    }
}
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值