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