【字符串哈希】【莫队算法】bzoj3207 花神的嘲讽计划Ⅰ
既然询问的长度是确定的,那么我们可以将所有长度为K的字串弄个哈希值出来,这样字串存在性=>哈希值存在性。
自然上溢哈希,base=107比较不错。
序列长度n=>n-K+1
询问区间[x,y]=>[x,y-K+1]
注意特判x是否>y-K+1
然后我们注意到没有修改,于是将哈希值离散化后,莫队大法好。
#include<cstdio> #include<cmath> #include<algorithm> using namespace std; typedef unsigned long long ull; int f,C; inline void R(int &x){ C=0;f=1; for(;C<‘0‘||C>‘9‘;C=getchar())if(C==‘-‘)f=-1; for(x=0;C>=‘0‘&&C<=‘9‘;C=getchar())(x*=10)+=(C-‘0‘); x*=f; } #define N 200001 #define seed 107 ull seedK=1; int n,m,K,a[N<<1],c[N],en,en2,X; int num[N],b[N<<1],sum=1; bool anss[N]; struct Point{ull v;int p;}t[N<<1]; struct Ask{int l,r,x,p;}Q[N]; bool operator < (const Point &a,const Point &b){return a.v<b.v;} bool operator < (const Ask &a,const Ask &b) {return num[a.l]!=num[b.l] ? num[a.l]<num[b.l] : a.r<b.r;} void Mo_Make_Block() { int sum=1,sz=sqrt(n); if(!sz) sz=1; for(;sum*sz<n;++sum) { int r=sum*sz; for(int i=(sum-1)*sz+1;i<=r;++i) num[i]=sum; } for(int i=(sum-1)*sz+1;i<=n;++i) num[i]=sum; } int main() { R(n); R(m); R(K); for(int i=1;i<=K;++i) seedK=seedK*seed; for(int i=1;i<=n;++i) R(c[i]); ull hs=0; for(int i=1;i<=K;++i) hs=hs*seed+(ull)c[i]; for(int i=K+1;i<=n;++i) { t[++en].v=hs; t[en].p=en; hs=hs*seed+(ull)c[i]; hs-=c[en]*seedK; } t[++en].v=hs; t[en].p=en; int Record=en; for(int i=1;i<=m;++i) { R(Q[i].l); R(Q[i].r); Q[i].p=i; Q[i].r=Q[i].r-K+1; hs=0; for(int j=1;j<=K;++j) { R(X); hs=hs*seed+(ull)X; } t[++en].v=hs; t[en].p=en; } sort(t+1,t+en+1); a[t[1].p]=++en2; for(int i=2;i<=en;++i) { if(t[i].v!=t[i-1].v) ++en2; a[t[i].p]=en2; } en=Record; for(int i=1;i<=m;++i) Q[i].x=a[++en]; Mo_Make_Block(); sort(Q+1,Q+m+1); for(int i=Q[1].l;i<=Q[1].r;++i) ++b[a[i]]; if(Q[1].l<=Q[1].r) anss[Q[1].p]=b[Q[1].x]; else anss[Q[1].p]=0; for(int i=2;i<=m;++i) { if(Q[i].l<Q[i-1].l) for(int j=Q[i-1].l-1;j>=Q[i].l;--j) ++b[a[j]]; else for(int j=Q[i-1].l;j<Q[i].l;++j) --b[a[j]]; if(Q[i].r<Q[i-1].r) for(int j=Q[i-1].r;j>Q[i].r;--j) --b[a[j]]; else for(int j=Q[i-1].r+1;j<=Q[i].r;++j) ++b[a[j]]; if(Q[i].l<=Q[i].r) anss[Q[i].p]=b[Q[i].x]; else anss[Q[i].p]=0; } for(int i=1;i<=m;++i) puts(anss[i]?"No":"Yes"); return 0; }
郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。