[cf1483F]Exam
对于字符串$s_{i}$,考虑(作为$s_{i}$的子串)与$s_{i}$有贡献的$s_{j}$
枚举$s_{i}$的前缀$t$,考虑所有是$t$后缀的$s_{j}$,显然仅有其中最长的可能有贡献
建立ac自动机,那么$s_{j}$即该前缀跳fail指针时第一个结束节点,可以预处理出
同时,注意到$s_{j}$有贡献当且仅当满足以下条件:
1.不存在其余被找到的串,使得其所在的区间包含$s_{j}$(维护左端点即可)
2.对于所有能跳fail指针能跳到$s_{j}$的前缀,均跳到了$s_{j}$(对两者分别计数,前者即子树求和)
时间复杂度为$o(n\log n)$,可以通过
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define N 1000005 4 #define D 26 5 queue<int>q; 6 vector<int>pos[N],e[N]; 7 int n,V,l,ans,ed[N],dep[N],ch[N][D],nex[N],dfn[N],sz[N],Pos[N],cnt[N]; 8 char s[N]; 9 struct TA{ 10 int f[N]; 11 int lowbit(int k){ 12 return (k&(-k)); 13 } 14 void update(int k,int x){ 15 while (k<=V){ 16 f[k]+=x; 17 k+=lowbit(k); 18 } 19 } 20 int query(int k){ 21 int ans=0; 22 while (k){ 23 ans+=f[k]; 24 k-=lowbit(k); 25 } 26 return ans; 27 } 28 }T; 29 void dfs(int k){ 30 dfn[k]=++dfn[0],sz[k]=1; 31 for(int i=0;i<e[k].size();i++){ 32 if (!ed[e[k][i]])ed[e[k][i]]=ed[k]; 33 dfs(e[k][i]),sz[k]+=sz[e[k][i]]; 34 } 35 } 36 int main(){ 37 scanf("%d",&n),V=1; 38 for(int i=1;i<=n;i++){ 39 scanf("%s",s+1),l=strlen(s+1); 40 int k=1; 41 for(int j=1;j<=l;j++){ 42 if (!ch[k][s[j]-'a']){ 43 ch[k][s[j]-'a']=++V; 44 dep[V]=dep[k]+1; 45 } 46 k=ch[k][s[j]-'a'],pos[i].push_back(k); 47 } 48 ed[k]=k; 49 } 50 for(int i=0;i<D;i++) 51 if (ch[1][i])nex[ch[1][i]]=1,q.push(ch[1][i]); 52 while (!q.empty()){ 53 int k=q.front(); 54 q.pop(); 55 for(int i=0;i<D;i++) 56 if (ch[k][i]){ 57 int j=nex[k]; 58 while ((j>1)&&(!ch[j][i]))j=nex[j]; 59 if (ch[j][i])j=ch[j][i]; 60 nex[ch[k][i]]=j,q.push(ch[k][i]); 61 } 62 } 63 for(int i=2;i<=V;i++)e[nex[i]].push_back(i); 64 dfs(1); 65 for(int i=1;i<=n;i++){ 66 int t=0,mn=1e9; 67 reverse(pos[i].begin(),pos[i].end()); 68 for(int j=0;j<pos[i].size();j++){ 69 int k=pos[i][j],x=ed[k]; 70 if (!j)x=ed[nex[k]]; 71 if (!x)continue; 72 if (!cnt[x])Pos[++t]=x; 73 cnt[x]++; 74 if (mn<=dep[k]-dep[x])cnt[x]=-1e9; 75 else mn=dep[k]-dep[x]; 76 } 77 for(int j=0;j<pos[i].size();j++)T.update(dfn[pos[i][j]],1); 78 for(int j=1;j<=t;j++){ 79 int k=Pos[j]; 80 if (T.query(dfn[k]+sz[k]-1)-T.query(dfn[k]-1)==cnt[k])ans++; 81 cnt[k]=0; 82 } 83 for(int j=0;j<pos[i].size();j++)T.update(dfn[pos[i][j]],-1); 84 } 85 printf("%d\n",ans); 86 return 0; 87 }