【BZOJ4943】【NOI2017】蚯蚓排队(哈希)

【BZOJ4943】【NOI2017】蚯蚓排队(哈希)

题面

BZOJ
洛谷
UOJ

题解

记得去年看网络同步赛的时候是一脸懵逼的。
昨天看到\(zsy\)做了,今天就看了看。。
这不是\(Hash\)的傻逼题吗。。。
呜。。。
开链表存一下前驱后继,因为询问长度不超过\(50\)
那么,总的串的个数不超过\(50n\),暴力\(hash\)一下然后拿哈希表存一下就好了。
我开始用的map然后TLE飞了

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<set>
#include<map>
#include<vector>
#include<queue>
using namespace std;
#define ull unsigned long long
#define ll long long
#define RG register
#define MAX 222222
#define MOD 998244353
const int base=233;
inline int read()
{
    RG int x=0,t=1;RG char ch=getchar();
    while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
    if(ch=='-')t=-1,ch=getchar();
    while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
    return x*t;
}
char ch[10000010];
ull pw[MAX],has[MAX];
int nt[MAX],lt[MAX],a[MAX],g[MAX<<1];
int n,m;
const int mod=7654321;
struct Hash_Table
{
    int h[mod],cnt;struct Line{int len,next,w;ull s;}e[10000000];
    void Add(int len,ull s,int w)
    {
        int u=s%mod;
        for(int i=h[u];i;i=e[i].next)
            if(e[i].len==len&&e[i].s==s)
            {e[i].w=(e[i].w+w)%MOD;return;}
        e[++cnt]=(Line){len,h[u],w,s};h[u]=cnt;
    }
    int Query(int len,ull s)
    {
        int u=s%mod;
        for(int i=h[u];i;i=e[i].next)
            if(e[i].len==len&&e[i].s==s)
                return e[i].w;
        return 0;
    }
}Hash;
void Link(int x,int y)
{
    nt[x]=y;lt[y]=x;
    ull ls=0;int tot=0;
    for(int i=x,len=49;i&&len;i=lt[i],--len)
    {
        ull s=0;ls+=a[i]*pw[tot++];s=ls;int l=tot+1;
        for(int j=y;j&&l<=50;j=nt[j],++l)s=s*base+a[j],Hash.Add(l,s,1);
    }
}
void Cut(int x)
{
    int y=nt[x];ull ls=0;int tot=0;
    for(int i=x,len=49;i&&len;i=lt[i],--len)
    {
        ull s=0;ls+=a[i]*pw[tot++];s=ls;int l=tot+1;
        for(int j=y;j&&l<=50;j=nt[j],++l)s=s*base+a[j],Hash.Add(l,s,MOD-1);
    }
    nt[x]=lt[y]=0;
}
int Query(int len)
{
    int l=strlen(ch+1),ret=1;ull s=0; 
    for(int i=1;i<len;++i)s=s*base+ch[i]-48;
    ch[0]='0';
    for(int i=len;i<=l;++i)
    {
        s=s*base+ch[i]-48;
        s-=pw[len]*(ch[i-len]-48);
        ret=1ll*ret*Hash.Query(len,s)%MOD;
    }
    return ret;
}
int main()
{
    pw[0]=1;for(int i=1;i<MAX;++i)pw[i]=pw[i-1]*base;
    n=read();m=read();
    for(int i=1;i<=n;++i)Hash.Add(1,a[i]=read(),1);
    while(m--)
    {
        int opt=read();
        if(opt==1)
        {
            int x=read(),y=read();
            Link(x,y);
        }
        else if(opt==2){Cut(read());}
        else
        {
            scanf("%s",ch+1);int k=read();
            printf("%d\n",Query(k));
        }
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/cjyyb/p/9260663.html
今日推荐