洛谷P3823/LOJ2303/UOJ315/BZOJ4943[NOI2017]蚯蚓排队(字符串哈希+哈希表)
看见神刀手我好像想到了什么。。。
字符串匹配问题。很明显要用字符串哈希,而且发现题目中的$k$很小,考虑把长度小于等于$k$的字串哈希值都暴力存进哈希表哈希套哈希,那么匹配的时候就可以做到接近$O(1)$。
连接和删除时,新增或减少的子串一定跨越断点,也就是一定由前串的后缀和后串的前缀拼成,枚举即可。
复杂度$O(mk^2+\sum{|s|)}$,还是可以过的。
#include<cstdio> #include<cctype> typedef unsigned long long ull; const int P=19260817; const int mod=998244353; const int N=200050; char rB[1<<21],*rS,*rT,wB[1<<21]; int wp=-1; inline char gc(){return rS==rT&&(rT=(rS=rB)+fread(rB,1,1<<21,stdin),rS==rT)?EOF:*rS++;} inline void flush(){fwrite(wB,1,wp+1,stdout);wp=-1;} inline void pc(char c){if(wp+1==(1<<21))flush();wB[++wp]=c;} inline int rd(){ char c=gc(); while(!isdigit(c))c=gc(); int x=c&15; for(c=gc();isdigit(c);c=gc())x=(x<<3)+(x<<1)+(c&15); return x; } short buf[15]; inline void wt(int x){ short l=-1; while(x>9){ buf[++l]=x%10; x/=10; } pc(x|48); while(l>=0)pc(buf[l--]|48); pc('\n'); } int a[N],lst[N],nxt[N]; ull f[N]; char s[10000050]; struct Hash{ int h[P],l[N<<7],cnt[N<<7],nxt[N<<7],sz; ull v[N<<7]; inline void ins(ull x,int len){ int pos=x%P,k=h[pos]; for(;k;k=nxt[k])if(l[k]==len&&v[k]==x){++cnt[k];return;} v[++sz]=x;l[sz]=len;cnt[sz]=1;nxt[sz]=h[pos];h[pos]=sz; } inline void del(ull x,int len){ for(int k=h[x%P];k;k=nxt[k])if(l[k]==len&&v[k]==x){--cnt[k];return;} } inline int query(ull x,int len){ for(int k=h[x%P];k;k=nxt[k])if(l[k]==len&&v[k]==x)return cnt[k]; return 0; } }h; inline int rds(){ char c=gc(); int len=1; while(!isdigit(c))c=gc(); for(s[0]=c,c=gc();isdigit(c);c=gc())s[len++]=c; return len; } int main(){ int n=rd(),q=rd(),i,j,opt,x,y,l1,l2,ans; ull res,tmp; for(f[0]=1ull,i=1;i<n;++i)f[i]=f[i-1]*7ull; for(i=1;i<=n;++i)h.ins(a[i]=rd(),1); while(q--){ opt=rd(); if(opt==1){ x=rd();y=rd(); nxt[lst[y]=x]=y; for(i=x,l1=1,res=0ull;i&&l1<50;i=lst[i],++l1){ tmp=(res+=a[i]*f[l1-1]); for(j=y,l2=1;j&&l1+l2<=50;j=nxt[j],++l2)h.ins(tmp=tmp*7ull+a[j],l1+l2); } }else if(opt==2){ lst[y=nxt[x=rd()]]=0;nxt[x]=0; for(i=x,l1=1,res=0ull;i&&l1<50;i=lst[i],++l1){ tmp=(res+=a[i]*f[l1-1]); for(j=y,l2=1;j&&l1+l2<=50;j=nxt[j],++l2)h.del(tmp=tmp*7ull+a[j],l1+l2); } }else if(opt==3){ l1=rds();x=rd(); for(res=i=0;i<x;++i)res=res*7ull+(s[i]&15); ans=h.query(res,x); for(i=x;i<l1&&ans;++i)ans=(ull)ans*h.query(res=(res-(s[i-x]&15)*f[x-1])*7ull+(s[i]&15),x)%mod; wt(ans); } } flush(); return 0; }
然后你会发现在洛谷上TLE了,这时开一个O2就过了不要慌
然后你发现在bzoj土豆机上玄学MLE了,这时候放心大胆地把Hash里面的N<<7继续开大到50000050就过了
或许是数组越界?