标签:alt bzoj2434 题意 论文 -- struct ace pac ide
(一下只供自己复习用,目的是对比这几个题,所以写得不详细。需要细节的可以参考其他博主)
【BZOJ3172:单词】
题目:
某人读论文,一篇论文是由许多(N)单词组成。但他发现一个单词会在论文中出现很多次,现在想知道每个单词分别在论文中出现多少次。N<=200,总单词长度不超过10^6。
思路:
简单题,建立AC自动机,插入的时候每个位置都++,代表以当前位置为后缀的字符串的个数,用于fail转移时累加。然后build得到fail指针;最后从叶子向根累加。
#include<bits/stdc++.h> using namespace std; const int maxn=1000010; char c[maxn]; int ans[maxn],pos[210],N; struct Trie { int ch[maxn][26],cnt,times,fail[maxn],q[maxn],head,tail; Trie(){ cnt=times=head=tail=0; } int insert(){ int Now=0,L=strlen(c+1); for(int i=1;i<=L;i++){ if(!ch[Now][c[i]-‘a‘]) ch[Now][c[i]-‘a‘]=++cnt; Now=ch[Now][c[i]-‘a‘]; ans[Now]++; } return Now; } void build() { for(int i=0;i<26;i++) if(ch[0][i]) q[++head]=ch[0][i]; while(tail<head){ int Now=q[++tail]; for(int i=0;i<26;i++){ if(ch[Now][i]){ fail[ch[Now][i]]=ch[fail[Now]][i]; q[++head]=ch[Now][i]; } else ch[Now][i]=ch[fail[Now]][i]; } } for(int i=tail;i>=1;i--) ans[fail[q[i]]]+=ans[q[i]]; } }T; int main() { scanf("%d",&N); for(int i=1;i<=N;i++){ scanf("%s",c+1); pos[i]=T.insert(); } T.build(); for(int i=1;i<=N;i++) printf("%d\n",ans[pos[i]]); return 0; }
【BZOJ2434阿狸的打字机】:
题目:
给定N个字符串。现在又Q个问题,每次问题给出(i,j),求第i个字符串在第j个字符串里出现的次数。 1<=N<=10e5;1<=M<=10e5;输入总长<=10e5
思路:
因为上一题是单次讯问,而且是整体求,所以一次拓扑倒序累加即可,但是此题是多次询问,而且是针对Trie树上代表的两个字符串之间的包含次数,不能整体法。 正解: 1,先建立AC自动机;2,得到fail树;3,对fail树进行DFS得到DFS序;4,在Trie树上dfs求解。
【字符串】BZOJ上面几个AC自动机求最为字串出现次数的题目
标签:alt bzoj2434 题意 论文 -- struct ace pac ide
原文地址:https://www.cnblogs.com/hua-dong/p/9004685.html