• [NOI2017]蚯蚓排队(链表+hash)


    这题看题面感觉挺玄学的,但其实会挂链式hash就能暴力切了,就是纸老虎,考察选手的语文水平。不过三年没写挂链hash也应该写一下了……

    首先模数设成自然溢出ull,然后挂链时的模数取2^24。然后就可以直接hash了。对于3操作直接O(Σ|S|)询问即可,对于1、2操作,直接暴力加、减长度不超过50的字符,毕竟k<=50,这是个关键性条件。所以暴力能切了。

    下面分析时间复杂度:先假设没有2操作,因为每一个位置只有长度不超过50的,每次加的数量也是不超过50的,这样总复杂度是均摊O(nk)的;再考虑2操作,因为2操作数量很少,而且每次只会至多影响O(k2)个数,因此考虑2操作后,复杂度是O(ck2)的,于是总复杂度是O(nk+ck2+Σ|S|)。注意hash不能用map,要挂链,因为map自带大常数和log,为什么不能unordered_map呢?因为这是NOI,不能用c++11。

    #include<bits/stdc++.h>
    using namespace std;
    typedef unsigned long long ull;
    const int N=5e5+7,p=19260817,mod=998244353,gloid=(1<<24)-1;
    int n,m,q,a[N],pre[N],nxt[N],cnt[N],f[150];
    ull h[150],pw[150];
    char s[11000000];
    struct Hash{
        struct edge{ull x;int v,nxt;}e[21000000];
        int hd[gloid+1],ecnt;
        void add(ull x,int d)
        {
            int u=x&gloid;
            for(int i=hd[u];i;i=e[i].nxt)if(e[i].x==x){e[i].v+=d;return;}
            e[++ecnt]=(edge){x,d,hd[u]},hd[u]=ecnt;
        }
        int query(ull x)
        {
            int u=x&gloid;
            for(int i=hd[u];i;i=e[i].nxt)if(e[i].x==x)return e[i].v;
            return 0;
        }
    }mp;
    void merge()
    {
        int x,y,L=51,R=50;scanf("%d%d",&x,&y);
        memset(f,0,sizeof f);
        for(int i=x;i&&L>1;i=pre[i])f[--L]=a[i];
        for(int i=y;i&&R<100;i=nxt[i])f[++R]=a[i];
        for(int i=1;i<=R;i++)h[i]=h[i-1]*p+f[i];
        for(int i=L;i<=50;i++)
        for(int j=51;j<=min(R,i+49);j++)
        mp.add(h[j]-h[i-1]*pw[j-i+1],1);
        nxt[x]=y,pre[y]=x;
    }
    void split()
    {
        int x,y,L=51,R=50;scanf("%d",&x),y=nxt[x];
        memset(f,0,sizeof f);
        for(int i=x;i&&L>1;i=pre[i])f[--L]=a[i];
        for(int i=y;i&&R<100;i=nxt[i])f[++R]=a[i];
        for(int i=1;i<=R;i++)h[i]=h[i-1]*p+f[i];
        for(int i=L;i<=50;i++)
        for(int j=51;j<=min(R,i+49);j++)
        mp.add(h[j]-h[i-1]*pw[j-i+1],-1);
        nxt[x]=pre[y]=0;
    }
    int query()
    {
        scanf("%s",s+1);
        int len=strlen(s+1),ret=1,k;
        scanf("%d",&k);
        ull val=0;
        if(k==1)
        {
            for(int i=1;i<=len;i++)ret=1ll*ret*cnt[s[i]]%mod;
            return ret;
        }
        for(int i=1;i<=len;i++)
        {
            val=val*p+s[i];
            if(i>k)val-=pw[k]*s[i-k];
            if(i>=k)ret=1ll*ret*mp.query(val)%mod;
        }
        return ret;
    }
    int main()
    {
        scanf("%d%d",&n,&q);
        pw[0]=1;for(int i=1;i<=50;i++)pw[i]=pw[i-1]*p;
        for(int i=1;i<=n;i++)scanf("%d",&a[i]),a[i]+='0',cnt[a[i]]++;
        while(q--)
        {
            int op;scanf("%d",&op);
            if(op==1)merge();
            else if(op==2)split();
            else printf("%d
    ",query());
        }
    }
    View Code
  • 相关阅读:
    初步了解Ajax
    什么是applet
    FilterLog代码分析
    Async分析
    HttpServletRequest hrequest
    xml的定义用途
    企业级与应用级的区别
    未来规划
    黄金点游戏
    hashCode与eqauls
  • 原文地址:https://www.cnblogs.com/hfctf0210/p/11050317.html
Copyright © 2020-2023  润新知