bzoj3207花神的嘲讽计划Ⅰ
题意:http://www.lydsy.com/JudgeOnline/problem.php?id=3207
给定一个原字符串和m个询问,每次查询原字符串[l,r]内是否包含给定字符串s (len(s)<=20且len(s)相同)
sol :考虑hash,将原串没len(s)位hash一次放入桶中,再将每次询问hash后在桶中查询(感觉很像rk-hash)
因为每次[l,r]转移到[l,r±1]、[l±1,r]都是从桶中取出or放入一个数,复杂的O(1),可以使用莫队算法
P.S.需要离散化而不能取模,否则memset复杂度爆炸
#include<iostream> #include<algorithm> #include<cstdio> #include<cstring> #include<cmath> #define int long long using namespace std; const int Mx=100010; const int p=23333333LL; struct Node { int x,y,val,num; } str[Mx]; bool cmp1 (Node a,Node b) { return a.x<b.x; } bool cmp2 (Node a,Node b) { return a.y<b.y; } int n,m,k,temp,a[Mx],h[Mx],ton[p+10],ans[Mx]; signed main() { scanf("%lld%lld%lld",&n,&m,&k); for(int i=1;i<=n;i++) scanf("%lld",&a[i]); for(int i=1;i<=m;i++) { int Tmp[50],tmp=1;str[i].num=i; scanf("%lld%lld",&str[i].x,&str[i].y); for(int j=1;j<=k;j++) scanf("%lld",&Tmp[j]); for(int j=k;j>=1;j--) str[i].val+=tmp*Tmp[j],tmp*=37,tmp%=p,str[i].val%=p; if(i==1) temp=tmp/37; } for(int i=k,tmp=1;i>=1;i--) h[1]+=tmp*a[i],tmp*=37,tmp%=p,h[1]%=p; for(int i=k+1;i<=n;i++) h[i-k+1]=(((h[i-k]-(a[i-k]*temp))*37+a[i])%p+p)%p; sort(str+1,str+1+m,cmp1); for(int i=1;i<=m;i+=sqrt(m)) sort(str+i,str+min(m,i+(int)sqrt(m)),cmp2); for(int i=1;i<=m;i++) { if(i%(int)sqrt(m)==1||i==1) { memset(ton,0,sizeof(ton)); for(int j=str[i].x;j<=str[i].y;j++) ton[(h[j]%p+p)%p]++; } else { for(int j=str[i-1].x,to=str[i].x;j!=to;) { if(j<to) ton[(h[j]%p+p)%p]--,j++; else j--,ton[(h[j]%p+p)%p]++; } for(int j=str[i-1].y,to=str[i].y;j!=to;) { if(j<to) j++,ton[(h[j-k]%p+p)%p]++; else ton[(h[j-k]%p+p)%p]--,j--; } } ans[str[i].num]=ton[str[i].val]; } for(int i=1;i<=m;i++) { if(ans[i]==0) puts("Yes"); else puts("No"); } return 0; }