- 题意:给n个字符串,问每个字符串在所有串里出现几次。
- 思路:判断一个整串与其它串之间的包含关系通常用AC自动机。fail树是我们想象中的树,但是它可以帮助我们更好的理解AC自动机。
1.fail树上的每个前缀都对应fail树里面的节点。通常节点存cnt[]表示有多少个串经过该点(即多少个前缀)
2.fail树中祖先节点是子孙节点的后缀,其中父亲是最长严格后缀。反过来,每个节点是它的子树里面节点的后缀。
通常一个串包含于另一个串我们理解为:一个串是另一个串的前缀的后缀。(因为前缀是节点,后缀在fail树上有意义)
当然这道题直接求FAIL树中该节点子树的cnt和。
- easy code:
#include<bits/stdc++.h>
using namespace std;
const int N=1e6+5;
char s[N];
int pos[N],n;
struct AC {
int fail[N],nd,go[N][27],cnt[N],Q[N],hd,tl,st[N],tp;
bool mark[N];
AC() {nd=tl=0;hd=1;}
void Insert(int &u) {
u=0;
int sz=strlen(s);
for(int i=0;i<sz;i++) {
int x=s[i]-'a';
if(!go[u][x])go[u][x]=++nd;
u=go[u][x];
cnt[u]++;
}
}
void gt_fail() {
for(int i=0;i<26;i++) if(go[0][i])Q[++tl]=go[0][i];
while(hd<=tl) {
int u=Q[hd++];st[++tp]=u;
for(int i=0;i<26;i++) {
if(go[u][i]) fail[go[u][i]]=go[fail[u]][i],Q[++tl]=go[u][i];
else go[u][i]=go[fail[u]][i];
}
}
}
void solve() {
while(tp) {int u=st[tp--];cnt[fail[u]]+=cnt[u];}
for(int i=1;i<=n;i++) printf("%d\n",cnt[pos[i]]);
}
}A;
int main() {
scanf("%d",&n);
for(int i=1;i<=n;i++) {scanf("%s",s);A.Insert(pos[i]);}
A.gt_fail();
A.solve();
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· winform 绘制太阳,地球,月球 运作规律
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人