题目:
Danganronpa
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 131072/131072 K (Java/Others)Total Submission(s): 827 Accepted Submission(s): 443
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) .
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) .
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.
T≤10
For each test case, n,m≤105 , 1≤|Ai|,|Bj|≤104 , ∑|Ai|≤105 , ∑|Bj|≤105
For all test case, ∑|Ai|≤6∗105 , ∑|Bj|≤6∗105 , Ai and Bj consist of only lowercase English letters
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.
T≤10
For each test case, n,m≤105 , 1≤|Ai|,|Bj|≤104 , ∑|Ai|≤105 , ∑|Bj|≤105
For all test case, ∑|Ai|≤6∗105 , ∑|Bj|≤6∗105 , 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
Author
SXYZ
Source
Recommend
wange2014
题意:字符串匹配,多个模式串匹配源串。
思路:AC自动机模板题。
代码:
//AC 自动机
#include <stdio.h>
#include <string.h>
#include <queue>
using namespace std;
inline int Max(int a,int b)
{
return a>b?a:b;
}
inline int Min(int a,int b)
{
return a>b?b:a;
}
#define maxnode 600010
#define sigma_size 26
struct Trie
{
int ch[maxnode][sigma_size];//下一指针
int val[maxnode];//匹配进度
int haha[maxnode];//节点i的成功匹配数
int f[maxnode];//失配指针
int sz;//size
//初始化
void init()
{
sz=1;
memset(ch,0,sizeof(ch));
memset(val, 0, sizeof(val));
memset(f,0,sizeof(f));
memset(haha,0,sizeof(haha));
}
//字符 c 的 index
int idx(char c)
{
return c-'a';
}
//插入串 s
int insert(char *s)
{
//
int u = 0, len = strlen(s);
for(int i = 0; i < len; i++)
{
//获取index
int c = idx(s[i]);
if(!ch[u][c]) ch[u][c] = sz++;//无路则建立指针到最后一个节点
u = ch[u][c];//到下一节点
}
val[u] ++; //将串结束的位置的val++
return u; //返回串S 结束位置的指针
}
//计算失败指针
void getFail()
{
queue<int> q;
for(int i = 0; i<sigma_size; i++)
if(ch[0][i]) q.push(ch[0][i]);//处理根节点
//将根节点的所有下一节点加入队列
while(!q.empty())
{
int r = q.front();
q.pop();
//取队首为r
//遍历r的所有下级
for(int c = 0; c<sigma_size; c++)
{
int u = ch[r][c];
if(!u)continue;//如果下一节点是根节点,跳过
//将r的下级加入队列
q.push(u);
int v = f[r];
///沿失配边走上去 如果失配后有节点 且 其子节点c存在则结束循环
while(v && ch[v][c] == 0) v = f[v];
f[u] = ch[v][c];//改变失配指针
}
}
}
//匹配 串T
void find(char *T)
{
int len = strlen(T), j = 0;//j为当前节点编号(0代表根节点)
for(int i = 0; i < len; i++)
{
int c = idx(T[i]);
while(j && ch[j][c]==0) //当j不是根节点且j到c无路(失配)
j = f[j];//走失配指针到下一节点(回滚)
//循环结束时:
//j 为根节点 或 j到c有路(可配)
j = ch[j][c];//j到下一节点,若j为根节点且没有路,则j还会走到根节点
int temp = j;
//标记整个路上的
while(temp)//当temp不是根
{
haha[temp]++;//在temp节点的进度+1
temp = f[temp];//回退到失败后节点
}
}
}
};
Trie ac;
char P[100011][10010];
int ans[100010];
char S1[100010];
int main()
{
int t,m,n;
scanf("%d",&t);
while(t--)
{
ac.init();
scanf("%d%d",&m,&n);
for(int i = 1; i <= m; i++)
{
scanf("%s",P[i]);
}
for(int i = 1; i <= n; i++)
{
scanf("%s",S1);
ans[i] = ac.insert(S1);
}
ac.getFail();
for(int i = 1; i <= m; i++)
{
memset(ac.haha,0,sizeof(ac.haha));
ac.find(P[i]);
int sum = 0;
for(int i=1; i <= n; i++)
sum += ac.haha[ans[i]];
printf("%d\n",sum);
}
}
return 0;
}