题目
思路
暴力解法:对于每个最长匹配,迭代跳fail,累计贡献。时间复杂度 O ( n 2 ) O(n^2) O(n2)。
优化:只标记最长匹配,最后用拓扑排序计算贡献。时间复杂度 O ( n ) O(n) O(n)。
代码
#include <bits/stdc++.h>
using namespace std;
const int N = 2e6 + 5;
const int M = 2e5 + 5;
int tr[N][26];
char s[N];
int ans[M];
int out[M];
int fail[N];
int ct;
vector<int> id[N];
void insert(char s[], int x)
{
int p = 0;
for (int i = 1; s[i]; i++)
{
if (!tr[p][s[i] - 'a'])
tr[p][s[i] - 'a'] = ++ct;
p = tr[p][s[i] - 'a'];
}
id[p].emplace_back(x);
}
int vis[N];
void build()
{
queue<int> q;
for (int i = 0; i < 26; i++)
if (tr[0][i])
q.push(tr[0][i]);
while (q.size())
{
int p = q.front();
q.pop();
for (int i = 0; i < 26; i++)
{
if (tr[p][i])
{
fail[tr[p][i]] = tr[fail[p]][i], q.push(tr[p][i]);
vis[tr[fail[p]][i]]++;
}
else
{
tr[p][i] = tr[fail[p]][i];
}
}
}
}
void get()
{
int p = 0;
for (int i = 1; s[i]; ++i)
{
p = tr[p][s[i] - 'a'];
ans[p]++;
}
}
bool fuck[N];
void topo()
{
queue<int> q;
for (int i = 1; i <= ct; i++)
{
if (!vis[i])
q.push(i), fuck[i] = 1;
}
while (q.size())
{
int i = q.front();
q.pop();
vis[fail[i]]--;
if (!vis[fail[i]])
q.push(fail[i]), fuck[fail[i]] = 1;
ans[fail[i]] += ans[i];
}
}
int main()
{
int n;
scanf("%d", &n);
for (int i = 1; i <= n; i++)
{
scanf("%s", s + 1);
insert(s, i);
}
scanf("%s", s + 1);
build();
get();
topo();
for (int i = 1; i <= ct; i++)
{
if (id[i].size())
{
int temp = ans[i];
for (auto &it : id[i])
out[it] = temp;
}
}
for (int i = 1; i <= n; i++)
printf("%d\n", out[i]);
return 0;
}
/*
*/