链接
https://acm.hdu.edu.cn/showproblem.php?pid=7064
题意
$T$ $(T\le 5)$ 个测试样例,主串 $s$ 长度不超过 $1e5$,每次有 $n$ 个询问,每次询问一个长度不超过 $30$ 的字符串 $a$,求其在主串中最多不重叠出现了多少次。$(\sum{|s|}\le 4e5,\sum{|a|}\le 4e5)$
思路
对 $n$ 个串建立 AC 自动机,遍历主串在AC 自动机上走,每次暴力往上跳 fail 指针,记录每个节点最后出现的位置,如果不重叠就 $+1$。
代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83
| #include <bits/stdc++.h> #define SZ(x) (int)(x).size() #define ALL(x) (x).begin(),(x).end() #define PB push_back #define EB emplace_back #define MP make_pair #define FI first #define SE second using namespace std; typedef double DB; typedef long double LD; typedef long long LL; typedef unsigned long long ULL; typedef pair<int,int> PII; typedef vector<int> VI; typedef vector<PII> VPII;
const int N=3e5+5; struct AC { int tr[N][26],fail[N],len[N],id[N],last[N],tot[N],sz; void init() { for(int i=0;i<=sz;i++) { for(int j=0;j<26;j++) tr[i][j]=0; fail[i]=tot[i]=0; } sz=0; } void insert(const string &s,int i) { int u=0; for(auto c:s) { int v=c-'a'; if(!tr[u][v]) { tr[u][v]=++sz; len[sz]=len[u]+1; last[sz]=0xc0c0c0c0; } u=tr[u][v]; } id[i]=u; } void build() { queue<int> q; for(int v=0;v<26;v++) if(tr[0][v]) q.push(tr[0][v]); while(SZ(q)) { int u=q.front(); q.pop(); for(int v=0;v<26;v++) { if(tr[u][v]) fail[tr[u][v]]=tr[fail[u]][v],q.push(tr[u][v]); else tr[u][v]=tr[fail[u]][v]; } } } } ac; int main() { ios::sync_with_stdio(false); cin.tie(nullptr); int T;cin>>T; while(T--) { ac.init(); string s;cin>>s; int n;cin>>n; for(int i=1;i<=n;i++) { string t;cin>>t; ac.insert(t,i); } ac.build(); int u=0; for(int i=0;i<SZ(s);i++) { int v=s[i]-'a'; u=ac.tr[u][v]; int t=u; while(t) { if(ac.last[t]+ac.len[t]<=i) { ++ac.tot[t]; ac.last[t]=i; } t=ac.fail[t]; } } for(int i=1;i<=n;i++) cout<<ac.tot[ac.id[i]]<<'\n'; } return 0; }
|