• [noi1754]SA


    枚举T中失配的位置i,容易发现能够成立当且仅当存在一个以$T[0,i)$为后缀的前缀$S[0,a)$且$T(i,|T|)$是$S(a,|S|)$的一个前缀
    考虑建立S的正序和倒序的两个后缀自动机,设$T[0,i)$对应点x(正序自动机中),$T(i,|T|)$对应点y(倒序自动机中),那么必然有$a-1in right(x)$和$a+1in right(y)$,具体地,如果将每一个前缀连向空一个字符的后缀,那么当且仅当两者的present子树中存在一条边
    然后有一个小问题,当$T[i]=S[a]$的时是不需要累计答案的,由于每一个位置分割都满足存在,所以要减去$出现次数|T|cdot 出现次数$
    如果把边看成$(x,y)$的点(按照dfs序),那么相当于二维数点的问题,用差分离线+线段树即可,时间复杂度$o(26|S|+log_{|S|}sum {|T|})$,常数较大
     
      1 #include<bits/stdc++.h>
      2 using namespace std;
      3 #define N 1000005
      4 #define L (k<<1)
      5 #define R (L+1)
      6 #define mid (l+r>>1)
      7 struct sam{
      8     int V,s[N],len[N],nex[N],ch[N][31],id[N],dfn[N],sz[N];
      9     vector<int>v[N];
     10 }S[2];
     11 struct qu{
     12     int p,id,x,y;
     13 };
     14 vector<int>v[N];
     15 vector<qu>Q[N];
     16 int n,las,pre[N],lst[N],ans[N],f[N<<2];
     17 char s[N];
     18 void add(int t,int c,int x){
     19     int p=las,np=las=S[t].id[x]=++S[t].V;
     20     S[t].s[np]=1;
     21     S[t].len[np]=S[t].len[p]+1;
     22     while ((p)&&(!S[t].ch[p][c])){
     23         S[t].ch[p][c]=np;
     24         p=S[t].nex[p];
     25     }
     26     if (!p)S[t].nex[np]=1;
     27     else{
     28         int q=S[t].ch[p][c];
     29         if (S[t].len[q]==S[t].len[p]+1)S[t].nex[np]=q;
     30         else{
     31             int nq=++S[t].V;
     32             S[t].nex[nq]=S[t].nex[q];
     33             S[t].len[nq]=S[t].len[p]+1;
     34             memcpy(S[t].ch[nq],S[t].ch[q],sizeof(S[t].ch[q]));
     35             S[t].nex[q]=S[t].nex[np]=nq;
     36             while ((p)&&(S[t].ch[p][c]==q)){
     37                 S[t].ch[p][c]=nq;
     38                 p=S[t].nex[p];
     39             }
     40         }
     41     }
     42 }
     43 void dfs(int p,int k){
     44     S[p].sz[k]=1;
     45     S[p].dfn[k]=++las;
     46     for(int i=0;i<S[p].v[k].size();i++){
     47         dfs(p,S[p].v[k][i]);
     48         S[p].s[k]+=S[p].s[S[p].v[k][i]];
     49         S[p].sz[k]+=S[p].sz[S[p].v[k][i]];
     50     }
     51 }
     52 void update(int k,int l,int r,int x){
     53     f[k]++;
     54     if (l==r)return;
     55     if (x<=mid)update(L,l,mid,x);
     56     else update(R,mid+1,r,x);
     57 }
     58 int query(int k,int l,int r,int x,int y){
     59     if ((l>y)||(x>r))return 0;
     60     if ((x<=l)&&(r<=y))return f[k];
     61     return query(L,l,mid,x,y)+query(R,mid+1,r,x,y);
     62 } 
     63 int main(){
     64     scanf("%s%d",s,&n);
     65     int l=strlen(s);
     66     las=S[0].V=S[1].V=S[0].id[0]=S[1].id[l]=1;
     67     for(int i=0;i<l;i++)add(0,s[i]-'a',i+1);
     68     las=1;
     69     for(int i=l-1;i>=0;i--)add(1,s[i]-'a',i);
     70     for(int i=1;i<=S[0].V;i++)S[0].v[S[0].nex[i]].push_back(i);
     71     las=0;
     72     dfs(0,1);
     73     for(int i=1;i<=S[1].V;i++)S[1].v[S[1].nex[i]].push_back(i);
     74     las=0;
     75     dfs(1,1);
     76     for(int i=1;i<=n;i++){
     77         scanf("%s",s);
     78         int ll=strlen(s);
     79         memset(pre,0,sizeof(pre));
     80         memset(lst,0,sizeof(lst));
     81         pre[0]=lst[ll]=1;
     82         for(int j=0;j<ll;j++)
     83             if (!S[0].ch[pre[j]][s[j]-'a'])break;
     84             else pre[j+1]=S[0].ch[pre[j]][s[j]-'a'];
     85         for(int j=ll-1;j>=0;j--)
     86             if (!S[1].ch[lst[j+1]][s[j]-'a'])break;
     87             else lst[j]=S[1].ch[lst[j+1]][s[j]-'a'];
     88         if (pre[ll])ans[i]-=ll*S[0].s[pre[ll]];
     89         for(int j=0;j<ll;j++)
     90             if ((pre[j])&&(lst[j+1])){
     91                 Q[S[0].dfn[pre[j]]-1].push_back(qu{-1,i,S[1].dfn[lst[j+1]],S[1].dfn[lst[j+1]]+S[1].sz[lst[j+1]]-1});
     92                 Q[S[0].dfn[pre[j]]+S[0].sz[pre[j]]-1].push_back(qu{1,i,S[1].dfn[lst[j+1]],S[1].dfn[lst[j+1]]+S[1].sz[lst[j+1]]-1});
     93             }
     94     }
     95     for(int i=0;i<l;i++)v[S[0].dfn[S[0].id[i]]].push_back(S[1].dfn[S[1].id[i+1]]);
     96     for(int i=1,j=0;i<=S[0].V;i++){
     97         for(int j=0;j<v[i].size();j++)update(1,1,S[1].V,v[i][j]);
     98         for(int j=0;j<Q[i].size();j++)ans[Q[i][j].id]+=Q[i][j].p*query(1,1,S[1].V,Q[i][j].x,Q[i][j].y);
     99     }
    100     for(int i=1;i<=n;i++)printf("%d
    ",ans[i]);
    101 }
    View Code
  • 相关阅读:
    使用systemctl管理指定服务需要做的配置
    挖矿病毒
    灰度发布系统
    血一般的教训,请慎用insert into select
    关于程序bug的闲谈
    来自一个网络监控软件的自述
    为什么CTO、技术总监、架构师都不写代码,还这么牛逼?
    原来 Elasticsearch 还可以这么理解
    爬了20W+条猫咪交易数据,它不愧是人类团宠
    NPUCTF2020 这是什么觅🐎
  • 原文地址:https://www.cnblogs.com/PYWBKTDA/p/13074257.html
Copyright © 2020-2023  润新知