AC自动机第一个样例都不对
查看原帖
AC自动机第一个样例都不对
867346
Fugeg楼主2023/11/30 00:03
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e6 + 20;
ll n,tr[maxn][30],last[300],fail[maxn],id[300],tot=0;
ll res[300];
string ss[300];
void insert(string s,int idx){
	int p=0;
	for(auto c:s){
		int u=c-'a';
		if(!tr[p][u]) tr[p][u]=++tot;
		p=tr[p][u];
	}
	last[idx]=p;//存这个单词在tr的哪
}
void build(){//建立失配数组
	queue<int>q;
	for(int i=0;i<26;i++)	if(tr[0][i]) q.push(tr[0][i]);
	
	int temp=0;
	while(!q.empty()){//因为fail必等于父亲节点fail+1 通过宽搜逐层来更新fail数组
		int u=q.front();
		q.pop();
		
		id[++temp]=u;//id数组(好像)按照BFS序来排
		
		for(int v=0;v<26;v++){
			if(tr[u][v]){
				q.push(tr[u][v]);
				fail[tr[u][v]]=tr[fail[u]][v];//父亲结点的fail,然后根据v来找
			}
			else tr[u][v]=tr[fail[u]][v];//在这直接 把父节点的子节点的失配指针 指向父节点这一层
		}
	}
}
void get(string s){
	int p=0;
	for(auto c:s){
		int u=c-'a';
		p=tr[p][u];
		res[p]++;
	}
	
	for(int i=tot;i;i--)	res[fail[id[i]]]+=res[id[i]];//(每一个树上的点)前缀已经出现过 把它的后缀也加一下
	//细节.应该是从tot到1 按照反bfs序来加res
}
void solve(){
	cin>>n;
	string t,s;
	for(int i=1;i<=n;i++){
		cin>>ss[i];
		insert(ss[i],i);//第几个插入字典树中
	}
	
	build();
	for(int i=1;i<=n;i++)	get(ss[i]);

	for(int i=1;i<=n;i++)	cout<<res[last[i]]<<endl;
}
int main(){
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	int T = 1;
	//	cin >> T;
	while (T--)	solve();
	return 0;
}

怎么事

2023/11/30 00:03
加载中...