把我坑惨了(1个小时) 将cin
换成scanf
cout
换成printf
就过了,
思路:询问区间值就用前缀和来做,将字符串通过一个hash函数映射在几乎不会重复的集合内,能够快速判断是否子字符串是否重复出现过,
- 用
unsigned long long
存hash值相当于自动对 2 64 2^{64} 264mod - 把字符串看成P进制下的数,如
S="abc"
h ( S ) = 1 ∗ p 2 + 2 ∗ p 1 + 3 ∗ p 0 h(S)=1*p^2+2*p^1+3*p^0 h(S)=1∗p2+2∗p1+3∗p0 - 在S后添加一个
char
c h ( s + c ) = h ( s ) ∗ p + ( c − ′ a ′ + 1 ) h(s+c)=h(s)*p+(c-'a'+1) h(s+c)=h(s)∗p+(c−′a′+1)同理char c
换成string
- h ( s + t ) = h ( s ) ∗ p t . s i z e ( ) + h ( t ) h(s+t)=h(s)*p^{t.size()}+h(t) h(s+t)=h(s)∗pt.size()+h(t) 就是进制进位计算,理解很简单
- 注意 计算区间子串hash值时,保证p进制的位是相同的然后在相减。
#include<iostream>
#include<cmath>
#include<cstring>
using namespace std;
const int maxn=1000005;
char str[maxn];
unsigned long long sum[maxn],f[maxn];
int main(){
freopen("a.txt","r",stdin);
scanf("%s",str+1);
int len=strlen(str+1);
int m;
scanf("%d",&m);
f[0]=1;
for(int i=1;i<=len;i++){
sum[i]=sum[i-1]*131+(str[i]-'a'+1);
f[i]=131*f[i-1];
}
for(int i=1;i<=m;i++){
int a,b,c,d;
scanf("%d %d %d %d",&a,&b,&c,&d);
if( sum[b]-sum[a-1]*f[b-a+1] == sum[d]-sum[c-1]*f[d-c+1]) printf("Yes\n");
else printf("No\n");
}
return 0;
}