• [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 }
    View Code
  • 相关阅读:
    sizeof和strlen的区别
    备注
    将一个正整数分解质因数
    malloc和new有什么区别
    用C来实现内存池
    句柄和指针的区别和联系是什么?
    c/c++ 宏中"#"和"##"的用法
    手机上网的原理
    数据类型转换(转自CSDN)
    vc debug和Release的切换
  • 原文地址:https://www.cnblogs.com/PYWBKTDA/p/15893831.html
Copyright © 2020-2023  润新知