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;
    }
}
View Code

 

posted @ 2020-10-29 23:41  朝暮不思  阅读(115)  评论(0编辑  收藏  举报