【BZOJ4943】蚯蚓排队(NOI2017)-链表+字符串哈希

测试地址:蚯蚓排队
做法:本题需要用到链表+字符串哈希。
因为k很小,所以用链表维护队列的形态,每次连接或断开暴力添加新增的子串信息即可,用字符串哈希来加速字符串的匹配即可。
根据一些神奇的复杂度分析,时间复杂度应该是O(),但是因为我太菜,最后一个点TLE+WA(分点测试TLE,BZOJ上WA),实在是没有办法了,先丢在这里吧……
以下是本人代码:

#include <bits/stdc++.h>
using namespace std;
typedef unsigned long long ll;
const ll mod=998244353;
const ll hashsiz=200003;
const ll Base=131;
int n,m,pre[200010],nxt[200010];
int first[hashsiz+10][51]={0},hashnxt[hashsiz+10][51],hashtot[51]={0};
ll bas[55],a[200010],hashlist[hashsiz+10][51],hashcnt[hashsiz+10][51];
char s[10000010];

ll hashfind(ll x,int k)
{
    ll pos=first[x%hashsiz][k];
    while(pos&&hashlist[pos][k]!=x) pos=hashnxt[pos][k];
    if (!pos) return -1;
    return pos;
}

void hashinsert(ll x,int k,ll cnt)
{
    ll pos=hashfind(x,k);
    if (pos!=-1) hashcnt[pos][k]+=cnt;
    else
    {
        hashlist[++hashtot[k]][k]=x;
        hashnxt[hashtot[k]][k]=first[x%hashsiz][k];
        hashcnt[hashtot[k]][k]=1;
        first[x%hashsiz][k]=hashtot[k];
    }
}

void maintain(int v,bool type)
{
    int nowl=v,nowr;
    ll lft=0,rht;
    for(int i=0;i<49&&nowl!=-1;i++)
    {
        lft+=a[nowl]*bas[i];
        rht=lft;
        nowl=pre[nowl];
        nowr=nxt[v];
        for(int j=1;j<=50-i-1&&nowr!=-1;j++)
        {
            rht=rht*Base+a[nowr];
            nowr=nxt[nowr];
            hashinsert(rht,i+j+1,type?(ll)1:(ll)-1);
        }
    }
}

int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
    {
        scanf("%lld",&a[i]);
        pre[i]=nxt[i]=-1;
        hashinsert(a[i],1,1);
    }

    bas[0]=1;
    for(int i=1;i<=55;i++)
        bas[i]=bas[i-1]*Base;

    for(int i=1;i<=m;i++)
    {
        int op,x,y;
        scanf("%d",&op);
        if (op==1)
        {
            scanf("%d%d",&x,&y);
            nxt[x]=y,pre[y]=x;
            maintain(x,1);
        }
        if (op==2)
        {
            scanf("%d",&x);
            maintain(x,0);
            pre[nxt[x]]=-1,nxt[x]=-1;
        }
        if (op==3)
        {
            scanf("%s%d",s,&x);
            int len=strlen(s);
            ll f=0,ans=1;
            for(int j=0;j<x-1;j++)
                f=f*Base+(ll)(s[j]-'0');
            for(int j=x-1;j<len;j++)
            {
                f=f*Base+(ll)(s[j]-'0');
                if (j-x>=0) f-=(ll)(s[j-x]-'0')*bas[x];
                int pos=hashfind(f,x);
                if (pos!=-1) ans=(ans*hashcnt[pos][x])%mod;
                else {ans=0;break;}
            }
            printf("%lld\n",ans);
        }
    }

    return 0;
}
posted @ 2018-05-10 21:46  Maxwei_wzj  阅读(95)  评论(0编辑  收藏  举报