• BZOJ3473: 字符串


    n<=100000个字符串,总长度<=100000,问每个字符串有多少子串至少出现在n个串中的m个。

    方法一:(未写)串在一起,后缀数组搞出来,然后height数组--排名相邻两个后缀的lcp搞出来,然后可能产生贡献的就是一段连续的height。对这段连续的height,如果有区间[L,R],满足R-L+1>=m-1,那么可以把[L,R]的后缀加上数字min(height_i),L<=i<=R,最后对每个字符串查询其所有后缀被+的次数。那优雅的做法就是看每个数的贡献,Li,Ri表示最大的区间满足height_i<=height_j,Li<=j<=Ri,然后记min(height_((Li)-1),height_((Ri)+1))=Gi,这个数的贡献就是:使得[Li,Ri]中的每个数加上了height_i-Gi。Li,Ri可用单调栈求出,区间加可用树状数组。

    不过有个小问题,如果一个后缀“越位”,即跨越到下一个字符串了,怎么办?那么在求height的时候留个心眼,令Hi表示第i个后缀到达其对应字符串末尾的长度,那么height(i+1,i)算出来后再min一下Hi和Hi+1即可。

    方法二:后缀自动机搞出来,看每个状态的贡献。先算出现次数。

    (1)沿着parent树做set的启发式合并。

    (2)每个字符串在自动机里走一发,每走一步沿parent更新一次。这样好像最坏L^(3/2)?

    接下来按pos从小到大算一次:每个状态沿着parent链走能得到多少出现次数>=m的字符串,这其实就是一个状态的贡献,因为每个状态代表的字符串包含了他的parent们。其实直接dfs一次就行,我写的太矫情还排了个序。

     1 #include<stdio.h>
     2 #include<string.h>
     3 #include<algorithm>
     4 #include<stdlib.h>
     5 //#include<iostream>
     6 //#include<assert.h>
     7 //#include<time.h>
     8 using namespace std;
     9 
    10 int n,m;
    11 #define maxn 200011
    12 struct samnode
    13 {
    14     samnode *ch[26],*pre;
    15     int pos,vis,tot,f;
    16     samnode() {memset(ch,0,sizeof(ch)); pre=NULL; vis=tot=f=0;}
    17 };
    18 struct SAM
    19 {
    20     samnode *root,*last;
    21     SAM() {root=new samnode; root->pos=0; last=root;}
    22     int idx(char c) {return c-'a';}
    23     void insert(char c,int p)
    24     {
    25         int id=idx(c);samnode *x=new samnode;
    26         x->pos=p;
    27         samnode *y=last;
    28         for (;y!=NULL && y->ch[id]==NULL;y=y->pre) y->ch[id]=x;
    29         last=x;
    30         if (y==NULL) x->pre=root;
    31         else
    32         {
    33             if (y->ch[id]->pos==y->pos+1) x->pre=y->ch[id];
    34             else
    35             {
    36                 samnode *z=y->ch[id],*w=new samnode;
    37                 memcpy(w->ch,z->ch,sizeof(z->ch));
    38                 w->pos=y->pos+1; w->pre=z->pre;
    39                 z->pre=x->pre=w;
    40                 for (;y!=NULL && y->ch[id]==z;y=y->pre) y->ch[id]=w;
    41             }
    42         }
    43     }
    44 }sam;
    45 
    46 char s[maxn];int end[maxn];
    47 samnode *tmp[maxn];int lt=0;
    48 bool cmp(const samnode *a,const samnode *b) {return a->pos<b->pos;}
    49 
    50 void dfs(samnode *x)
    51 {
    52     tmp[++lt]=x;x->vis=n+1;
    53     for (int i=0;i<26;i++) if (x->ch[i]!=NULL && x->ch[i]->vis!=n+1) dfs(x->ch[i]);
    54 }
    55 void dfs() {dfs(sam.root);}
    56 
    57 int main()
    58 {
    59     scanf("%d%d",&n,&m);
    60     for (int i=1;i<=n;i++)
    61     {
    62         scanf("%s",s+end[i-1]+1);
    63         end[i]=end[i-1]+strlen(s+end[i-1]+1);
    64         sam.last=sam.root;
    65         for (int j=end[i-1]+1;j<=end[i];j++) sam.insert(s[j],j-end[i-1]);
    66     }
    67     for (int i=1;i<=n;i++)
    68     {        
    69         samnode *p=sam.root;
    70         for (int j=end[i-1]+1;j<=end[i];j++)
    71         {
    72             p=p->ch[s[j]-'a'];
    73             for (samnode *q=p;q!=NULL && q->vis!=i;q=q->pre) q->vis=i,q->tot++;
    74         }
    75     }
    76     dfs();
    77     sort(tmp+1,tmp+1+lt,cmp);
    78     tmp[1]->f=0;
    79     for (int i=2;i<=lt;i++) tmp[i]->f=tmp[i]->pre->f+(tmp[i]->tot>=m?tmp[i]->pos-tmp[i]->pre->pos:0);
    80     #define LL long long
    81     for (int i=1;i<=n;i++)
    82     {
    83         LL ans=0;
    84         samnode *p=sam.root;
    85         for (int j=end[i-1]+1;j<=end[i];j++)
    86         {
    87             p=p->ch[s[j]-'a'];
    88             ans+=p->f;
    89         }
    90         printf("%lld ",ans);
    91     }
    92     return 0;
    93 }
    View Code
  • 相关阅读:
    正则表达式(常用正则总结)
    What is maven?
    二维数组的遍历使用foreach
    Installing Git
    Hive修改表名,列名,列注释,表注释,增加列,调整列顺序,属性名等操作
    有趣的开源项目集结完毕,HelloGitHub 月刊第 63 期发布啦!
    - zxvf
    tensorflow入门
    Postman v8.7.0
    springboot等javaweb项目将jar包安装(打包)到本地Maven仓库
  • 原文地址:https://www.cnblogs.com/Blue233333/p/7994494.html
Copyright © 2020-2023  润新知