• [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;
    }
    

  • 相关阅读:
    以太坊:深入理解Solidity-Solidity v0.5.0 重大更新
    以太坊:深入理解Solidity-合约
    以太坊:深入理解Solidity-表达式和控制结构
    我的友情链接
    我的友情链接
    我的友情链接
    我的友情链接
    我的友情链接
    我的友情链接
    我的友情链接
  • 原文地址:https://www.cnblogs.com/Troverld/p/14612776.html
Copyright © 2020-2023  润新知