做题之前:学会Hash表,用long long !!!!!!!!!!
这道题要求在线算法、一个Hash对应(7进制)、合并+分离
一头雾水………………
阅读题目次数*998244353……………………
k<=50直接上暴力合并拆解
其余的Hash表维护
具体看代码吧
#include<cstdio> #include<cstring> #define _for(i,a,b) for(register int i=(a) ;i<=(b);i=-~i) #define __for(i,a,b) for(register int i=(a);i>=(b);i=~-i) #define Re register int using namespace std; typedef long long ll; const int N=2e5+20,P=19260817,Q=1e7+20,mod=998244353; inline int re(){int x=0,f=0; char ch=getchar(); while(ch>'9'||ch<'0') f|=ch=='-',ch=getchar(); while(ch>='0'&&ch<='9') x=(x<<1)+(x<<3)+(ch^48),ch=getchar(); return f?-x:x; } int n,m,cnt,head[P+10],nxt[N],bef[N],val[N]; ll p[100],p10[100],num[100]; char s[Q]; struct zu { int nxt,num; ll val; }hashtable[P+10]; inline void add(ll Hash,ll q) //Hash表如果有Hash这个值&&有这个原值q,num++,否则新开一个点 { for(Re i=head[Hash];i;i=hashtable[i].nxt) if(hashtable[i].val==q) { hashtable[i].num++; return ; } hashtable[++cnt].num=1; hashtable[cnt].val=q; hashtable[cnt].nxt=head[Hash]; head[Hash]=cnt; } inline void dlt (ll Hash,ll q) { for(Re i=head[Hash];i;i=hashtable[i].nxt) if(hashtable[i].val==q) { hashtable[i].num--;//删除同理,就是加变减,题目保证有解 return ; } } inline int ask(ll Hash,ll q) { for(Re i=head[Hash];i;i=hashtable[i].nxt) if(hashtable[i].val==q)//同理返回队列长度 return hashtable[i].num; return 0;//没这么长的长度返回0 } int s1[100],s2[100]; void unionn(int u,int v) { int l1=0,l2=0; ll hash1=0,q1=0,hash2=0,q2=0; nxt[u]=v; bef[v]=u; for(Re i=u;i&&l1<49;i=bef[i]) {//将u与u之前最长50的串取出来,注意在s1中的串是反着的 s1[++l1]=val[i]; hash1=(hash1+val[i]*p[l1-1])%P; q1+=(val[i]*p10[l1-1]); } for(Re i=v;i&&l2<49;i=nxt[i]) s2[++l2]=val[i]; //将v与v之后最长50的串取出来,注意在s2中的串是正着的 __for(i,l1,1) {//s1是反串,最前面的字符在l1的位置,所以倒序枚举 hash2=0; q2=0; for(Re j=1;j<=l2&&i+j<=50;j++) {//s2是正串,最后面的字符在1的位置,所以正序枚举 hash2=(hash2*7+s2[j])%P; q2=q2*10+s2[j];//Hash值与原值累加,塞到Hash表中 add((hash1*p[j]%P+hash2)%P,q1*p10[j]+q2); } hash1=((hash1-p[i-1]*s1[i])%P+P)%P; q1-=(p10[i-1]*s1[i]); //将hash1和q1向下减 } } void cut (int u,int v) {//来一句与合并同理,行吗?O(∩_∩)O哈哈~ int l1=0,l2=0; ll hash1=0,hash2,q1=0,q2; nxt[u]=0; bef[v]=0; for(Re i=u;i&&l1<49;i=bef[i]) { s1[++l1]=val[i]; hash1=(hash1+val[i]*p[l1-1])%P; q1+=(val[i]*p10[l1-1]); } for(Re i=v;i&&l2<49;i=nxt[i]) s2[++l2]=val[i]; __for(i,l1,1) { hash2=0; q2=0; for(Re j=1;i+j<=50&&j<=l2;j++) { hash2=(hash2*7+s2[j])%P; q2=q2*10+s2[j]; dlt((hash1*p[j]%P+hash2)%P,q1*p10[j]+q2); } hash1=((hash1-p[i-1]*s1[i])%P+P)%P; q1-=(s1[i]*p10[i-1]); } } int main() { n=re(),m=re(); _for(i,1,n) val[i]=re(),num[val[i]]++; p[0]=p10[0]=1; _for(i,1,50) p[i]=p[i-1]*7%P,p10[i]=p10[i-1]*10; //之所以用7,是因为题目保证蚯蚓长度不超过6 int op,x,y,len,k; ll Hash,q,ans; while(m--) { op=re(); if(op==1) {//合并x,y x=re(),y=re(); unionn(x,y); } else if(op==2) {//分离x,x的下一个 x=re(); cut(x,nxt[x]); } else { scanf("%s",s+1); k=re(); len=strlen(s+1); Hash=q=0; ans=1; if(k==1) //特别的,如果询问长度为1的串,因为之前我也没有加过,所以在读入的时候开一个桶来统计答案 { _for(i,1,len) ans=ans*num[s[i]^48]%mod; printf("%lld\n",ans); continue; } _for(i,1,k) { Hash=(Hash*7+(s[i]^48))%P; q=q*10+(s[i]^48); } ans=ask(Hash,q)%mod; _for(i,k+1,len) { Hash=(((Hash-(s[i-k]^48)*p[k-1]%P+P)%P)*7+(s[i]^48))%P; q=(q-(s[i-k]^48)*p10[k-1])*10+(s[i]^48); //更新原值和Hash值 ans=ans*ask(Hash,q)%mod; } printf("%lld\n",ans); } } return 0; } /* Hash表 暴力模拟蚯蚓队伍的合并和分离 */