[NOI2017] 蚯蚓排队

XLI.[NOI2017] 蚯蚓排队

算算数据范围,可以哈希,只需要将所有长度在 \(50\) 以内的串扔进哈希表,然后询问时找到对应的串的出现次数即可。

这里的哈希表必须用双哈希,其中第一维开在数组范围内,然后第二维作为链表挂在后面,因此范围可以无限大。不过因为要在 int 内处理,因此我两个模数分别取了 4999999299999977,底数是 117,这样就在 int 内了。

维护蚯蚓排队的过程可以手写链表。

比较悲催的一点是,为了卡空间,我写了链表中回收废弃节点的操作,但是却忘记用了,然后空间还开的是卡过后的大小,最后很是debug一会才找出来。

时间复杂度 \(O\Big(n+mk^2+\sum |s|\Big)\)

代码:

#include<bits/stdc++.h>
using namespace std;
int n,m,a[200100],pv1[60],pv2[60];
const int mod1=4999999,mod2=299999977,bs1=11,bs2=7,mod=998244353;
struct HashTable{
	int head[mod1],nxt[200100],val[200100],num[200100],cnt,bin[200100],tp;
	HashTable(){memset(head,-1,sizeof(head));}
	int newnode(){return tp?bin[tp--]:cnt++;}
	void ins(int x,int y,int d){
		for(int *i=&head[x];*i!=-1;i=&nxt[*i]){
			if(val[*i]!=y)continue;
			num[*i]+=d;if(!num[*i])bin[++tp]=*i,*i=nxt[*i];return;
		}
		int id=newnode();
		nxt[id]=head[x],val[id]=y,num[id]=d,head[x]=id;
	}
	int ask(int x,int y){for(int i=head[x];i!=-1;i=nxt[i])if(val[i]==y)return num[i];return 0;}
}ht[50];
struct List{
	int las,nex;
	List(){las=nex=-1;}
}l[200100];
int S,K;
char s[10001000];
void merge(){
	int x,y;
	scanf("%d%d",&x,&y);
	l[x].nex=y,l[y].las=x;
	for(int i=1;x!=-1&&i<50;x=l[x].las,i++){
		int p=0,q=0;
		for(int j=x,k=0;j!=-1&&k<50;j=l[j].nex,k++){
			p=(bs1*p+a[j])%mod1;
			q=(bs2*q+a[j])%mod2;
			if(k>=i)ht[k].ins(p,q,1);
		}
	}
}
void split(){
	int t,x,y;scanf("%d",&t),x=t,y=l[x].nex;
	for(int i=1;x!=-1&&i<50;x=l[x].las,i++){
		int p=0,q=0;
		for(int j=x,k=0;j!=-1&&k<50;j=l[j].nex,k++){
			p=(bs1*p+a[j])%mod1;
			q=(bs2*q+a[j])%mod2;
			if(k>=i)ht[k].ins(p,q,-1);
		}
	}
	l[t].nex=l[y].las=-1;
}
int query(){
	scanf("%s%d",s,&K),S=strlen(s);
	int p=0,q=0,res=1;
	for(int i=0;i<S;i++){
		if(i>=K)(p+=mod1-pv1[K-1]*(s[i-K]-'0')%mod1)%=mod1,(q+=mod2-pv2[K-1]*(s[i-K]-'0')%mod2)%=mod2;
//		printf("%d %d\n",p,q);
		p=(p*bs1+(s[i]-'0'))%mod1,q=(q*bs2+(s[i]-'0'))%mod2;
		if(i>=K-1)res=1ll*res*ht[K-1].ask(p,q)%mod;
		if(!res)return 0;
	}
	return res;
}
int main(){
	pv1[0]=pv2[0]=1;for(int i=1;i<50;i++)pv1[i]=pv1[i-1]*bs1%mod1,pv2[i]=pv2[i-1]*bs2%mod2;
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++)scanf("%d",&a[i]),ht[0].ins(a[i],a[i],1);
	int qt=0;
	for(int i=1,tp;i<=m;i++){
		scanf("%d",&tp);
		if(tp==1)merge();
		if(tp==2)split();
		if(tp==3)printf("%d\n",query());
	}
	return 0;
}

posted @ 2021-04-02 23:09  Troverld  阅读(90)  评论(0编辑  收藏  举报