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("]\n");
        }
    }
};
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;
}

 

 
posted @ 2017-10-03 10:42  hinata_hajime  阅读(160)  评论(0编辑  收藏  举报