Gym101741K Consistent Occurrences(AC自动机)
多模式串匹配问题,因为要求每个串不重复出现的次数,我们只需要对于每个串维护一个len,如果匹配到当前串的末尾并且到之前匹配的长度大于等于len,那么说明是新的答案
我采用的方法是对于每个独立串的末尾标记一下,这样我们去做自动机的时候就能够知道是否匹配,但是每次都要走到根,因为这样才可以覆盖到所有的串。
但是有个问题,字符串不一定不等,因此我们哈希一下,对于相同的字符串,只做第一个,后面的答案跟他一样即可
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int N=5e5+10; struct node{ int cnt; node * nxt[27]; node * fail; vector<node *> num; }*rt; node pool[N]; node *pos[N]; int n,m,idx; int cnt[N]; int len[N]; int id[N]; int last[N]; string s; map<string,int> m1; int dd[N]; void insert(string s,int x){ node *p=rt; int i; for(i=0;i<s.size();i++){ int sign=s[i]-'a'; if(p->nxt[sign]==NULL) p->nxt[sign]=pool+(++idx); p=p->nxt[sign]; if(i==(int)s.size()-1&&!p->cnt){ p->cnt=x; } } } void build(){ int i; queue<node *> q; rt->fail=rt; for(i=0;i<26;i++){ if(rt->nxt[i]){ rt->nxt[i]->fail=rt; rt->num.push_back(rt->nxt[i]); q.push(rt->nxt[i]); } else{ rt->nxt[i]=rt; rt->nxt[i]->fail=rt; } } while(q.size()){ auto t=q.front(); q.pop(); for(i=0;i<26;i++){ if(t->nxt[i]){ t->nxt[i]->fail=t->fail->nxt[i]; t->fail->nxt[i]->num.push_back(t->nxt[i]); q.push(t->nxt[i]); } else{ t->nxt[i]=t->fail->nxt[i]; } } } } void query(){ int i; node *p=rt; memset(last,-1,sizeof last); for(i=0;i<n;i++){ int sign=s[i]-'a'; p=p->nxt[sign]; node *tmp=p; while(p!=rt){ if(p->cnt){ if(i-last[p->cnt]>=len[p->cnt]){ cnt[p->cnt]++; last[p->cnt]=i; } } p=p->fail; } p=tmp; } } int main(){ ios::sync_with_stdio(false); cin>>n>>m; int i; rt=pool; cin>>s; for(i=1;i<=m;i++){ string s1; cin>>s1; len[i]=(int)s1.size(); insert(s1,i); if(m1[s1]){ dd[i]=m1[s1]; } else{ m1[s1]=i; } } build(); query(); for(i=1;i<=m;i++){ if(dd[i]) cnt[i]=cnt[dd[i]]; cout<<cnt[i]<<endl; } }
没有人不辛苦,只有人不喊疼