• HDU 5384 Danganronpa(AC自动机)


    Danganronpa

    Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others)
    Total Submission(s): 1402    Accepted Submission(s): 754


    Problem Description
    Danganronpa is a video game franchise created and developed by Spike Chunsoft, the series' name is compounded from the Japanese words for "bullet" (dangan) and "refutation" (ronpa).

    Now, Stilwell is playing this game. There are n verbal evidences, and Stilwell has m "bullets". Stilwell will use these bullets to shoot every verbal evidence.

    Verbal evidences will be described as some strings Ai, and bullets are some strings Bj. The damage to verbal evidence Ai from the bullet Bj is f(Ai,Bj).
    f(A,B)=i=1|A||B|+1[ A[i...i+|B|1]=B ]
    In other words, f(A,B) is equal to the times that string B appears as a substring in string A.
    For example: f(ababa,ab)=2, f(ccccc,cc)=4

    Stilwell wants to calculate the total damage of each verbal evidence Ai after shooting all m bullets Bj, in other words is mj=1f(Ai,Bj).
     
    Input
    The first line of the input contains a single number T, the number of test cases.
    For each test case, the first line contains two integers n, m.
    Next n lines, each line contains a string Ai, describing a verbal evidence.
    Next m lines, each line contains a string Bj, describing a bullet.

    T10
    For each test case, n,m105, 1|Ai|,|Bj|104, |Ai|105, |Bj|105
    For all test case, |Ai|6105, |Bj|6105, Ai and Bj consist of only lowercase English letters
     
    Output
    For each test case, output n lines, each line contains a integer describing the total damage of Ai from all m bullets, mj=1f(Ai,Bj).
     
    Sample Input
    1 5 6 orz sto kirigiri danganronpa ooooo o kyouko dangan ronpa ooooo ooooo
     
    Sample Output
    1 1 0 3 7
     
    AC自动机的基本运用,多元匹配
    代码如下:
    #include <stdio.h>
    #include <algorithm>
    #include <iostream>
    #include <string.h>
    #include <queue>
    using namespace std;
    typedef long long ll;
    struct Trie
    {
        int Next[500010][26];//26是这里讨论26个小写字母的情况,根据情况修改
        int fail[500010],end[500010];//end数组表示以该节点结尾的字符串的数量
        int root,L;//L用来标记节点序号,以广度优先展开的字典树的序号
        int newnode()  //建立新节点
        {
            for(int i = 0;i < 26;i++)
                Next[L][i] = -1;     //将该节点的后继节点域初始化
            end[L++] = 0;
            return L-1;    //返回当前节点编号
        }
        void init() //初始化操作
        {
            L = 0;
            root = newnode();
        }
        void insert(char buf[])
        {
            int len = strlen(buf);
            int now = root;
            for(int i = 0;i < len;i++)
            {
                if(Next[now][buf[i]-'a'] == -1)  //如果未建立当前的后继节点,建立新的节点
                    Next[now][buf[i]-'a'] = newnode();
                now = Next[now][buf[i]-'a'];
            }
            end[now]++;//以该节点结尾的字符串数量增加1
        }
        void build()
        {
            queue<int>Q; //用广度优先的方式,将树层层展开
            fail[root] = root;
            for(int i = 0;i < 26;i++)
                if(Next[root][i] == -1)
                    Next[root][i] = root;
                else
                {
                    fail[Next[root][i]] = root;
                    Q.push(Next[root][i]);
                }
            while( !Q.empty() )
            {
                int now = Q.front();
                Q.pop();
                for(int i = 0;i < 26;i++)
                    if(Next[now][i] == -1)
                        Next[now][i] = Next[fail[now]][i];//该段的最后一个节点匹配后,跳到拥有最大公共后缀的fail节点继续匹配
                    else
                    {
                        fail[Next[now][i]]=Next[fail[now]][i];//当前节点的fail节点等于它前驱节点的fail节点的后继节点
                        Q.push(Next[now][i]);
                    }
            }
        }
        ll query(string buf)
        {
            int len = buf.size();
            int now = root;
            ll res = 0;
            for(int i = 0;i < len;i++)
            {
                now = Next[now][buf[i]-'a'];
                int temp = now;
                while( temp != root )
                {
                    res += end[temp];//加上以当前节点结尾的字符串数
                    temp = fail[temp];//每次找最大公共后缀对应的fail节点
                }
            }
            return res;
        }
        void debug()
        {
            for(int i = 0;i < L;i++)
            {
                printf("id = %3d,fail = %3d,end = %3d,chi = [",i,fail[i],end[i]);
                for(int j = 0;j < 26;j++)
                    printf("%2d",Next[i][j]);
                printf("]
    ");
            }
        }
    };
    string buf[100010];
    Trie ac;
    char str[100010];
    int main()
    {
        int  t,n,ans,m;
        scanf("%d",&t);
        while(t--)
        {
            ac.init();
           scanf("%d%d",&n,&m);
           for(int i=0;i<n;i++)
              cin>>buf[i];
         for(int i=0;i<m;i++){
            scanf("%s",str);
            ac.insert(str);
         }
             ac.build();
           for(int i=0;i<n;i++)
           {
            cout<<ac.query(buf[i])<<endl;
           }
        }
        return 0;
    }
     
  • 相关阅读:
    python 类 专有方法
    当请求进入Nginx后,每个HTTP执行阶段的作用
    jquery 监听不起效果的小问题汇总
    shell 脚本中 while 只执行一次
    LVS (Linux虚拟服务器)模型及算法
    TCP 通信时序及状态变迁
    Golang 谷歌搜索api 实现搜索引擎(前端 bootstrap + jquery)
    Golang 简单 http 代理转发
    Golang 简单静态web服务器
    Golang TCP转发到指定地址
  • 原文地址:https://www.cnblogs.com/a249189046/p/7623349.html
Copyright © 2020-2023  润新知