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");
}
}