题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6096

题意:给了一些模式串,然后再给出一些文本串的不想交的前后缀,问文本串在模式串的出现次数。

解法:

因为要求前缀后缀都包含的个数,所以可以把字符串a转换成a#a这样一个字符串,比如abca就转换成abca#abca

然后对于一组前缀a后缀b转换成b{a,比如ab ca,就是ca{ab,

然后对前缀后缀的串建立AC自动机,让主串去匹配,如上述例子,ca{ab满足为abca{abca的一个子串,也就是abca满足这个前缀后缀,所以问题,就转换成了典型的ac自动机匹配问题。

加个{的原因是为了只让后缀{前缀这种串能在AC自动机匹配到。

然后求答案的时候,需要对连接到自己的fail的位置累加一下,含义想一下就明白了。

#include <bits/stdc++.h>
using namespace std;
const int maxn = 1000010;
const int maxs = 30;
string s[maxn];
int d[maxn],pos[maxn],ans[maxn],st[maxn],len[maxn];
struct Acautomata{
int nxt[maxn][maxs],cnt[maxn],fail[maxn],match[maxn],dep[maxn];
int L, root;
int newnode(){
for(int i=0; i<maxs; i++) nxt[L][i]=-1;
cnt[L++]=0;
fail[L-1]=0;
return L-1;
}
void init(){
L = 0;
root = newnode();
}
int Insert(string a){
int now=root;
for(int i=0; a[i]; i++){
if(nxt[now][a[i]-'a']==-1){
nxt[now][a[i]-'a']=newnode();
dep[L-1]=i+1;
}
now=nxt[now][a[i]-'a'];
}
cnt[now]=1;
return now;
}
void build()
{
queue<int>q;
int now=root;
fail[0] = 0;
for(int i=0; i<maxs; i++){
if(nxt[now][i]==-1){
nxt[now][i]=root;
continue;
}
else{
fail[nxt[now][i]]=root;
q.push(nxt[now][i]);
}
}
while(!q.empty())
{
now = q.front();
q.pop();
for(int i=0; i<maxs; i++){
if(nxt[now][i]!=-1){
q.push(nxt[now][i]);
fail[nxt[now][i]] = nxt[fail[now]][i];
match[nxt[now][i]] = cnt[nxt[now][i]]?nxt[now][i]:match[nxt[fail[now]][i]];
}else{
nxt[now][i] = nxt[fail[now]][i];
}
}
}
}
void solve1(string a, int h){
int now=root;
int sz = a.size();
for(int i=0; i<sz; i++){
now=nxt[now][a[i]-'a'];
while(dep[now]>h){
now=fail[now];
}
ans[match[now]]++;
}
}
void solve2(){//累加答案,对连到自己的fail进行累加求和
memset(d, 0, sizeof(d));
int j, k = 0;
for(int i=0; i<L; i++) d[fail[i]]++;
for(int i=0; i<L; i++) if(!d[i]) st[k++]=i;
for(int i=0; i<k; i++){
j=fail[st[i]];
ans[j]+=ans[st[i]];
if(!(--d[j])){
st[k++]=j;
}
}
}
}ZXY;
int n, q;
int main()
{
int T;
scanf("%d", &T);
while(T--)
{
ZXY.init();
scanf("%d%d", &n,&q);
for(int i=0; i<n; i++){
cin>>s[i];
len[i] = s[i].size()+1;
string temp=s[i];
s[i]+=char('z'+1);
s[i]+=temp;
}
for(int i=0; i<q; i++){
string s1,s2;
cin>>s1>>s2;
s2 = s2 + char('z'+1);
s2 = s2 + s1;
pos[i] = ZXY.Insert(s2);
}
ZXY.build();
for(int i=0; i<n; i++){
ZXY.solve1(s[i],len[i]);
}
ZXY.solve2();
for(int i=0; i<q; i++) printf("%d\n", ans[pos[i]]);
for(int i=0; i<=ZXY.L; i++){
ans[i]=0;
ZXY.match[i]=0;
}
}
return 0;
}

最新文章

  1. EmguCV 阈值化
  2. [BTS] Can&#39;t update the assembly.
  3. Safari5及以下版本不支持Date的横杠字符串格式
  4. javascript 的button onclick事件不起作用的解决方法
  5. 集合函数AVG,SUM,MAX,MIN
  6. hive metastore异常 org.apache.thrift.protocol.TProtocolException: Missing version in readMessageBegin, old client
  7. JS随机数不重复
  8. CoCos2dx开发:更换导出的app名称和图标
  9. GLSL 变量属性
  10. expdp和impdp 使用注意事项
  11. BZOJ.2756.[SCOI2012]奇怪的游戏(二分 黑白染色 最大流ISAP)
  12. $trainClassLayer.find(&#39;input[name=data-item-checkbox]&#39;).eq(index).change();//激活第index+1那个checkbox
  13. .net正则表达式实例
  14. win10 损坏 bios?
  15. leetcode笔记:Bulls and Cows
  16. 〖Linux〗使用sed命令修改小端(little endian)存储的数据
  17. Ubuntu16.04安装Mono、MonoDevelop运行C#代码
  18. Linux磁盘管理,vi编辑器以及包管理器
  19. vim应用:终极解决windows系统gvim/vim的各种乱码(文件,菜单,提示信息)!
  20. (转)python类class中_init_函数以及参数self的简单解释

热门文章

  1. Docker的结构(6-13)
  2. POJ 3261 Milk Patterns (后缀数组,求可重叠的k次最长重复子串)
  3. POJ3421:X-factor Chains——题解
  4. Leetcode中字符串总结
  5. 牛客网 提高组第8周 T1 染色
  6. 【状压DP】【P2831】【NOIP2016D2T3】愤怒的小鸟
  7. GSM之AT操作命令详解20160615
  8. MyBatis代码生成工具mybatis-generator在Myeclipse10中的使用
  9. SFM
  10. Ubuntu 14.04 64bit下Caffe + Cuda6.5/Cuda7.0 安装配置教程