1 条题解

  • 0
    @ 2025-8-24 21:53:43

    自动搬运

    查看原文

    来自洛谷,原作者为

    avatar SuperJvRuo
    **

    搬运于2025-08-24 21:53:43,当前版本为作者最后更新于2018-03-10 09:48:12,作者可能在搬运后再次修改,您可在原文处查看最新版

    自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多

    以下是正文


    乍一看字符集是所有的走法,应该是68826*8*8*2的大小,但其实字符集应该是可能出现的所有单个字符共6+8+8+16+8+8+1,这样就可以直接用AC自动机了,速度与后缀数组做法基本相当,但是空间占用要大一些

    #include<iostream>
    #include<queue>
    #include<string>
    using namespace std;
    
    int trans[128];
    int cnt=0;
    void init()
    {
    	//建立字符到整数的映射
        int cnt=0;
        trans['K']=++cnt;
        trans['Q']=++cnt;
        trans['B']=++cnt;
        trans['N']=++cnt;
        trans['R']=++cnt;
        trans['P']=++cnt;
        trans['x']=++cnt;
        trans[0]=++cnt;
        for(char i='a';i<='h';++i)
        {
            trans[i]=++cnt;
        }
        for(char i='1';i<='8';++i)
        {
            trans[i]=++cnt;
        }
    }
    
    string name[2005];
    //定式名
    bool vis[2005];
    //是否出现
    
    struct Tree
    {
        int fail;
        int vis[26];
        int num;
    }AC[800005];
    //Trie树
    
    inline void Build(string s,int num)
    {
    	//建树
        int l=s.length();
        int now=0;
        for(int i=0;i<l;++i)
        {
            if(AC[now].vis[trans[s[i]]]==0)
            AC[now].vis[trans[s[i]]]=++cnt;
            now=AC[now].vis[trans[s[i]]];
        }
        AC[now].num=num;
    }
    
    void Get_fail()
    {
    	//BFS求fail
        queue<int> Q;
        for(int i=0;i<26;++i)
        {
            if(AC[0].vis[i]!=0)
            {
                AC[AC[0].vis[i]].fail=0;
                Q.push(AC[0].vis[i]);
            }
        }
        while(!Q.empty()) 
        {
            int u=Q.front();
            Q.pop();
            for(int i=0;i<26;++i)
            {
                if(AC[u].vis[i]!=0)
                {
                    AC[AC[u].vis[i]].fail=AC[AC[u].fail].vis[i];
                    Q.push(AC[u].vis[i]);
                }
                else
                AC[u].vis[i]=AC[AC[u].fail].vis[i];
            }
        }
    }
    
    void AC_Query(string s)
    {
        int l=s.length();
        int now=0;
        for(int i=0;i<l;++i)
        {
            now=AC[now].vis[trans[s[i]]];
            for(int t=now;t;t=AC[t].fail)
            {
                vis[AC[t].num]=1;
            } 
        }
    }
    
    int main()
    {
        init();
        ios::sync_with_stdio(false);
        int n,m,k;
        string s;
        cin>>n>>m;
        for(int i=1;i<=n;++i)
        {
            string now;
            cin>>k;
            //读入k以后还没有换行,此处需要getline一下
            getline(cin,name[i]);
            getline(cin,name[i]);
            for(int j=0;j<k;++j)
            {
                cin>>s;
                now+=s;
                //全都接起来
            }
            Build(now,i);
        }
        AC[0].fail=0;
        Get_fail();
        
        string now;
        for(int i=0;i<m;++i)
        {
            cin>>s;
            now+=s;
            //接起来
        }
        AC_Query(now);
        //匹配
        for(int i=1;i<=n;++i)
        {
            if(vis[i])
            cout<<name[i]<<'\n';
        }
        return 0;
    }
    

    • 1

    信息

    ID
    2840
    时间
    6000ms
    内存
    125MiB
    难度
    6
    标签
    递交数
    0
    已通过
    0
    上传者