BZOJ4943 NOI2017蚯蚓排队(哈希+链表)
能看懂题就能想到正解。维护所有长度不超过k的数字串的哈希值即可,用链表维护一下蚯蚓间连接情况。由于这样的数字串至多只有nk个,计算哈希值的总复杂度为O(nk),而分裂的复杂度为O(ck^2),询问复杂度为O(Σ|s|)。于是总复杂度为O(nk+ck^2+Σ|s|)。
手写哈希注意插入元素时考虑清楚,如果没有哈希冲突不需要更新哈希使用的链表,所以特判一下。
#include<iostream> #include<cstdio> #include<cmath> #include<cstdlib> #include<cstring> #include<algorithm> using namespace std; int read() { int x=0;char c=getchar(); while (c<'0'||c>'9') c=getchar(); while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar(); return x; } #define N 200010 #define S 10000010 #define K 50 #define P 19260817 #define MOD 998244353 #define G 7 #define ul unsigned long long int n,m,POW[K+1][10]; struct data{int x,pre,nxt; }a[N]; int ch[S]; int map[P+10],cnt[P+10],nxt[P+10]; ul value[P+10],POWv[K+1][10]; void ins(int x,ul v) { if (!map[x]) map[x]=1,value[x]=v,cnt[x]=1; else { int t; while (map[x]&&value[x]!=v) t=x,x=nxt[x]; if (map[x]) cnt[x]++; else map[x]=1,value[x]=v,cnt[x]=1,nxt[t]=x; } } void del(int x,ul v) { while (value[x]!=v) x=nxt[x]; cnt[x]--; } int query(int x,ul v) { while (map[x]&&value[x]!=v) x=nxt[x]; return cnt[x]; } int main() { n=read(),m=read(); for (int i=0;i<P-1;i++) nxt[i]=i+1;nxt[P-1]=0; for (int j=1;j<=9;j++) { POW[0][j]=j;for (int i=1;i<=K;i++) POW[i][j]=POW[i-1][j]*G%P; POWv[0][j]=j;for (int i=1;i<=K;i++) POWv[i][j]=POWv[i-1][j]*G; } for (int i=1;i<=n;i++) a[i].x=read(),ins(a[i].x,a[i].x); while (m--) { int op=read(); switch(op) { case 1: { int x=read(),y=read(); a[x].nxt=y,a[y].pre=x; for (int l=1,h=x;h&&l<K;h=a[h].pre,l++) { int hash=0;ul hashv=0; for (int i=1,t=h;i<=l;t=a[t].nxt,i++) hash=(hash*G+a[t].x)%P,hashv=hashv*G+a[t].x; for (int i=l+1,t=y;t&&i<=K;t=a[t].nxt,i++) { hash=(hash*G+a[t].x)%P,hashv=hashv*G+a[t].x; ins(hash,hashv); } } break; } case 2: { int x=read(),y=a[x].nxt; for (int l=1,h=x;h&&l<K;h=a[h].pre,l++) { int hash=0;ul hashv=0; for (int i=1,t=h;i<=l;t=a[t].nxt,i++) hash=(hash*G+a[t].x)%P,hashv=hashv*G+a[t].x; for (int i=l+1,t=y;t&&i<=K;t=a[t].nxt,i++) { hash=(hash*G+a[t].x)%P,hashv=hashv*G+a[t].x; del(hash,hashv); } } a[x].nxt=0;a[y].pre=0; break; } case 3: { char c=getchar();int l=0; while (c<'0'||c>'9') c=getchar(); while (c>='0'&&c<='9') ch[++l]=c^48,c=getchar(); int k=read(); int hash=0;ul hashv=0; for (int i=1;i<k;i++) hash=(hash*G+ch[i])%P,hashv=hashv*G+ch[i]; int ans=1; for (int i=k;i<=l;i++) { hash=(hash*G+ch[i]-POW[k][ch[i-k]]+P)%P, hashv=hashv*G+ch[i]-POWv[k][ch[i-k]]; ans=1ll*ans*query(hash,hashv)%MOD; } printf("%d\n",ans); } } } return 0; }