zoukankan      html  css  js  c++  java
  • 【题解】2019校内测试 字符串

    请自觉忽视解密后的输入……


    一道正常的题,一个奇怪的做法

    首先看到这个题就要想到AC自动机

    但一般的AC自动机只支持一次询问,否则会出现死循环

    原因是在建立fail指针的代码中的这句话:

    if (node[u].ch[i]) {
        node[node[u].ch[i]].fail=node[node[u].fail].ch[i];
    	q.push(node[u].ch[i]);
    } else {
    	node[u].ch[i]=node[node[u].fail].ch[i];
    }
    

    这句话意味着当当前节点没有某儿子时,儿子指针会指向失配节点的那个儿子

    那么就有可能有这种情况:

    所以我们要想一个办法来避免这种情况的发生

    最简单的做法:

    把多出来的儿子指针(图中蓝色指针)去掉

    换句话说,还原建fail指针之前的自动机

    于是就有了如下的代码:

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <queue>
    #include <map>
    #include <cmath>
    #define int long long
    using namespace std;
    
    const int N=2000010;
    
    struct note {
        int fail;
        int ch[26];
        int str_end;
    };
    
    int ch_bak[N][26];
    
    struct AC {
        note node[N];
        int siz;
        AC() {
            siz=1;
        }
        inline int id(char ch) {
            return ch-'a';
        }
        inline void insert(char s[],int val) {
            int len=strlen(s);
            int u=0;
            for(int i=0;i<len;i++) {
                int c=id(s[i]);
                if (!node[u].ch[c]) {
                    node[u].ch[c]=siz++;
                }
                u=node[u].ch[c];
            }
            node[u].str_end+=val;
        }
        inline void fail() {
            queue<int> q;
            while(!q.empty()) {
                q.pop();
            }
            for(int i=0;i<=siz;i++) {
                for(int j=0;j<=25;j++) {
                    ch_bak[i][j]=node[i].ch[j];
                }
                node[i].fail=0;
            }
            for(int i=0;i<26;i++) {
                if (node[0].ch[i]!=0) {
                    node[node[0].ch[i]].fail=0;
                    q.push(node[0].ch[i]);
                }
            }
            while(!q.empty()) {
    	    int u=q.front();
    	    q.pop();
    	    for(int i=0;i<26;i++) {
    		if (node[u].ch[i]) {
    	            node[node[u].ch[i]].fail=node[node[u].fail].ch[i];
    		    q.push(node[u].ch[i]);
    		} else {
    		    node[u].ch[i]=node[node[u].fail].ch[i];
    		}
    	    }
    	}
        }
        inline void back() {
            for(int i=0;i<=siz;i++) {
                for(int j=0;j<=25;j++) {
                    node[i].ch[j]=ch_bak[i][j];
                }
            }
        }
        inline int query(char s[]) {
            int len=strlen(s);
            int u=0,ans=0;
            for(int i=0;i<len;i++) {
                u=node[u].ch[id(s[i])];
                for(int t=u;t;t=node[t].fail) {
                    ans+=node[t].str_end;
                }
            }
            back();
            return ans;
        }
    };
    
    int n;
    char s[N];
    AC t;
    
    signed main() {
        scanf("%d",&n);
        int mask=0;
        for(int i=1;i<=n;i++) {
            int opx;
            scanf("%d %s",&opx,s);
            opx^=mask;
            if (opx==3) {
                t.fail();
                int qwq=t.query(s);
                mask^=abs(qwq);
                printf("%d
    ",qwq);
            } else {
                if (opx==1) {
                    t.insert(s,1);
                } else {
                    t.insert(s,-1);
                }
            }
        }
        return 0;
    }
    
    
    

    时间复杂度(O(m∑|s|)),按理来说过不去,可出题人并没有卡,加之常数较小,就这么过了……

  • 相关阅读:
    leetcode
    leetcode
    leetcode
    leetcode
    Postman
    Fiddler抓百度和bing搜索包
    Jmeter脚本录制
    Android Studio使用Maven国内镜像
    Open Live Writer
    PureXXX使用手记
  • 原文地址:https://www.cnblogs.com/tt66ea-blog/p/11311522.html
Copyright © 2011-2022 走看看