AC handle multiple string matching automata --cf1202E

si sj + intermediate has a cut point, we enumerate the cutting point i on t, that is t [i] required number si as the last character can be matched to t [i + 1] as the first character how much time can match sj

Then the sequence s n with ac build a robot, an automatic anti-build the machine and each of the positive and negative matching t once with SUM [] array record t [i] as the number of the last character string matching can be

Note: When seeking sum array, violence will obviously jump fail t, taking into account the statistical jump fail to match the string suffix, so when we build, you can put that fail can be added to the end now in the process fail pointer end up, thus avoiding the violent jump fail

#include<bits/stdc++.h>
using namespace std;
#define N 200005

struct Trie{
    int nxt[N][26],fail[N],end[N];
    int root,L;
    int newnode(){
        memset(nxt[L],-1,sizeof nxt[L]);
        end[L]=0;
        return L++;
    }
    void init(){
        L++;
        root=newnode();
    }
    void insert(char buf[]){
        int len=strlen(buf+1);
        int now=root;
        for(int i=1;i<=len;i++){
            if(nxt[now][buf[i]-'a']==-1)
                nxt[now][buf[i]-'a']=newnode();
            now=nxt[now][buf[i]-'a'];
        }
        end[now]++;
    }
    void build(){
        queue<int>q;
        fail[root]=root;
        for(int i=0;i<26;i++)
            if(nxt[root][i]==-1)
                nxt[root][i]=root;
            else {
                fail[nxt[root][i]]=root;
                q.push(nxt[root][i]);
            }
        while(q.size()){
            int now=q.front();
            q.pop(); 
            for(int i=0;i<26;i++)
                if(nxt[now][i]==-1)
                    nxt[now][i]=nxt[fail[now]][i];
                else {
                    fail[nxt[now][i]]=nxt[fail[now]][i];
                    end[nxt[now][i]]+=end[nxt[fail[now]][i]];
                    q.push(nxt[now][i]);
                }
        }
    }
    int sum[N];
    int query(char buf[]){
        int len=strlen(buf+1);
        int now=root;
        for(int i=1;i<=len;i++){
            now=nxt[now][buf[i]-'a'];
            sum[i]+=end[now];
        }
    }
}; 

char buf[N],t[N];
Trie t1,t2;
int n;
void reserve(char s[]){
    int i=1,j=strlen(s+1);
    while(i<j){
        swap(s[i],s[j]);
        ++i,--j;
    }
}

int main(){
    t1.init();
    t2.init();    
    scanf("%s%d",t+1,&n);
    for(int i=1;i<=n;i++){
        scanf("%s",buf+1);
        t1.insert(buf);
        reserve(buf);
        t2.insert(buf);
    }
    t1.build();
    t2.build();
    t1.query(t);
    reserve(t);
    t2.query(t);
    
    int len=strlen(t+1);
    long long ans=0;
    for(int i=0;i<len;i++)
        ans+=(long long)t1.sum[i]*t2.sum[len-i];
    cout<<ans<<'\n';
}

 

Guess you like

Origin www.cnblogs.com/zsben991126/p/11518657.html