分析

我们如何处理 。我们其实需要一点小技巧。我们发现, 如果出现在 中。那么一定有一个位置 满足 的后缀。 的一个前缀。那么我们就可以枚举每一个位置,看能够作为前缀的串的个数和作为后缀串的个数。最后答案为 。而求后缀,我们可以用 ,而求前缀有个小技巧,反转 后再插入 就是求前缀了。那么总的复杂度为 。一开始脑袋智商不在线,写了一个 的树状数组维护标记。也过了。代码都放下。

代码

#include<bits/stdc++.h>
using namespace std;
const int N = 6e5 + 100;
struct AcAm{
    int fail[N],ch[N][26],si[N],size;
    int insert(char *s) {
        int len = strlen(s + 1),u = 0;
        for(int i = 1;i <= len;i++) {int c = s[i] - 'a';if(!ch[u][c]) ch[u][c] = ++size;u = ch[u][c];}
        si[u]++;return u;
    }
    void build() {
        queue<int> q;for(int i=0;i<26;i++)if(ch[0][i])q.push(ch[0][i]);
        while(!q.empty()) { 
            int x=q.front();q.pop();for(int i = 0;i < 26;i++) {
                int y = ch[x][i];if(y) {fail[y]=ch[fail[x]][i];si[y]+=si[fail[y]];q.push(y);}
                else ch[x][i]=ch[fail[x]][i];
            }
        }
    }
    int query(int x) {return si[x];}
}t,rt;
int pos[N],rpos[N];
#define ll long long
int main() {
    static char ch[N];scanf("%s",ch+1);
    int m = strlen(ch + 1);int n;scanf("%d",&n);
    for(int i = 1;i <= n;i++) {
        static char S[N];scanf("%s",S+1);int len = strlen(S + 1);
        t.insert(S);reverse(S + 1,S + 1 + len);rt.insert(S);
    }
    t.build();rt.build();
    for(int i = 1,u = 0;i <= m;i++) {int c = ch[i]-'a';u = t.ch[u][c];pos[i]=t.query(u);}
    reverse(ch+1,ch+1+m);ll ans = 0;
    for(int i = 1,u = 0;i <= m;i++) {int c = ch[i]-'a';u = rt.ch[u][c];rpos[m-i+1]=rt.query(u);}
    for(int i = 1;i <= m;i++) {
        ans += pos[i] * 1ll * rpos[i + 1];
    }cout << ans << endl;
    return 0;
}



#include<bits/stdc++.h>
using namespace std;
const int N = 6e5 + 100;
struct Sam{
    vector<int> G[N];
    int L[N],R[N],id,T[N];
    int fail[N],ch[N][26],si[N],size;
    void add(int x,int k) {for(int i = x;i <= size + 1;i+=i&-i) T[i] += k;}
    int ask(int x) {int tot=0;for(int i = x;i;i-=i&-i) tot+=T[i];return tot;}
    void plus(int l,int r,int k) {add(l,k);add(r+1,-k);}
    int insert(char *s) {
        int len = strlen(s + 1),u = 0;
        for(int i = 1;i <= len;i++) {int c = s[i] - 'a';if(!ch[u][c]) ch[u][c] = ++size;u = ch[u][c];}
        si[u]++;return u;
    }
    void dfs(int x) {L[x]=++id;for(auto y:G[x])dfs(y);R[x]=id;}
    void build() {
        queue<int> q;for(int i=0;i<26;i++)if(ch[0][i])q.push(ch[0][i]);
        while(!q.empty()) { 
            int x=q.front();q.pop();for(int i = 0;i < 26;i++) {
                int y = ch[x][i];if(y) {fail[y]=ch[fail[x]][i];q.push(y);}
                else ch[x][i]=ch[fail[x]][i];
            }
        }for(int i=1;i<=size;i++)G[fail[i]].push_back(i);dfs(0);
        for(int i=1;i<=size;i++)plus(L[i],R[i],si[i]);
    }
    int query(int x) {return ask(L[x]);}
}t,rt;
int pos[N],rpos[N];
#define ll long long
int main() {
    static char ch[N];scanf("%s",ch+1);
    int m = strlen(ch + 1);int n;scanf("%d",&n);
    for(int i = 1;i <= n;i++) {
        static char S[N];scanf("%s",S+1);int len = strlen(S + 1);
        t.insert(S);reverse(S + 1,S + 1 + len);rt.insert(S);
    }
    t.build();rt.build();
    for(int i = 1,u = 0;i <= m;i++) {int c = ch[i]-'a';u = t.ch[u][c];pos[i]=t.query(u);}
    reverse(ch+1,ch+1+m);ll ans = 0;
    for(int i = 1,u = 0;i <= m;i++) {int c = ch[i]-'a';u = rt.ch[u][c];rpos[m-i+1]=rt.query(u);}
    for(int i = 1;i <= m;i++) {
//        cout << pos[i] << "  " << rpos[i + 1] << endl;
        ans += pos[i] * 1ll * rpos[i + 1];
    }cout << ans << endl;
    return 0;
}