题目:
题意:
定义两个字符串等价,当且仅当一个串中的
26
26
26中字母在对应各不相同的
26
26
26中字母后和另一个串相同
给出一个原串
s
s
s,有
m
m
m组形如
(
x
,
y
,
z
)
(x,y,z)
(x,y,z)的询问,表示从
x
x
x和
y
y
y开始,长度为
z
z
z的
s
s
s的两个子串是否等价
分析:
对于两个串是否等价,我们不难发现,只有当字母的排列相同时才有可能,还要保证每种字母对应的是不同的字母
所以我们可以想想如何去记录这样的东西,这,似乎是一种状态,那我们对于字符串每个字母单独记录
一个位置上是不是这种字母,用
1
/
0
1/0
1/0来表示,随便给个进制,状态就是把整个串的
1
/
0
1/0
1/0乘在一起,形如
10010011
10010011
10010011,当然具体的情况还是要看进制的(十进制被卡了我也不晓得为什么)
对于两个子串等价的判定,我们根据每种字母的状态,因为我们只关心这种字母的排列情况,而变成了什么字母并不影响答案的判定,所以把所有状态排个序,逐个比较
代码:
#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
#define LL long long
#define bace 200005
#define U unsigned
using namespace std;
inline LL read()
{
LL s=0,f=1; char c=getchar();
while(c<'0'||c>'9') {if(c=='-') f=-1;c=getchar();}
while(c>='0'&&c<='9') {s=s*10+c-'0';c=getchar();}
return s*f;
}
char s[200005];
int t[200005][30];
U LL M[200005];
U LL ksm(U LL x,U LL y)
{
U LL s;
while(y)
{
if(y&1) s*=x;
x*=x;y>>=1;
}
return s;
}
int q1[30],q2[30];
int main()
{
// freopen("data.in","r",stdin);
// freopen("1.out","w",stdout);
int n=read(),m=read();
scanf("%s",s+1);
for(int i=1;i<=n;i++)
{
for(int j=1;j<=26;j++) t[i][j]=t[i-1][j];
t[i][s[i]-'a'+1]++;
}
for(int i=1;i<=n;i++)
{
M[i]=M[i-1];M[i]=(U LL)M[i]*bace+1;
int k=i+1,l=1;
while(s[k]==s[k-1])
{
M[k]=M[i-1];l++;
M[k]=(U LL)M[k]*bace+l;
k++;
}
}
for(int i=1;i<=m;i++)
{
int x=read(),y=read(),z=read();
int a=x+z-1,b=y+z-1;
for(int k=1;k<=26;k++)
{
q1[k]=t[a][k]-t[x-1][k];
q2[k]=t[b][k]-t[y-1][k];
}
sort(q1+1,q1+27);sort(q2+1,q2+27);
int tf=0;
for(int k=1;k<=26;k++) if(q1[k]!=q2[k]) {tf=1;break;}
if(tf) {printf("NO\n");continue;}
U LL bc=ksm(bace,z);
U LL s1=M[a]-M[x-1]*bc,s2=M[b]-M[y-1]*bc;
if(s1==s2) printf("YES\n"); else printf("NO\n");
}
return 0;
}