• 【算法总结】字符串相关


    【KMP算法】

    〖模板代码

     1     n=strlen(a);m=strlen(b);
     2     for(int i=1;i<m;i++)
     3     {
     4         int j=f[i];
     5         while(j&&b[i]!=b[j])j=f[j];
     6         f[i+1]=b[i]==b[j]?j+1:0;
     7     }
     8     int j=0;
     9     for(int i=0;i<n;i++)
    10     {
    11         while(j&&b[j]!=a[i])j=f[j];
    12         if(b[j]==a[i])j++;
    13         if(j==m)printf("%d
    ",i-m+1);
    14     }
    View Code

    〖相关题目

    1.【bzoj1355】[Baltic2009]Radio Transmission

    题意:有一个字符串由某个字符串不断自我连接形成的字符串,这个字符串是不确定的,现在想知道它的最短长度是多少。

    分析:hzwerの博客

     1 #include<cstdio>
     2 #include<algorithm> 
     3 #include<cstring>
     4 #define LL long long
     5 using namespace std;
     6 const int N=1e6+5;
     7 int n,j,fail[N];
     8 char s[N];
     9 int read()
    10 {
    11     int x=0,f=1;char c=getchar();
    12     while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    13     while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
    14     return x*f;
    15 }
    16 int main()
    17 {
    18     n=read();
    19     scanf("%s",s+1);
    20     for(int i=2;i<=n;i++)
    21     {
    22         while(j&&s[j+1]!=s[i])j=fail[j];
    23         if(s[j+1]==s[i])j++;
    24         fail[i]=j;
    25     }
    26     printf("%d",n-fail[n]);
    27     return 0;
    28 }
    View Code

    2.【Codeforces Round #269 (Div. 2)】D. MUH and Cube Walls

    题意:给你一个长度为n(1<=n<=2e5)的一排积木,长度分别为a[](1<=a[]<=1e9)。 有一个长度为m(1<=m<=2e5)的一排积木,长度分别为b[](1<=b[]<=1e9)。问你,第一排积木有多少个位点i,使得[i+0,i+m-1]这一段积木,之间增减幅度与b[]的整体增减幅度相同。 增减幅度肯定产生于相邻的积木之间。 

    分析:hzwerの博客

     1 #include<cstdio>
     2 #include<algorithm> 
     3 #include<cstring>
     4 #define LL long long
     5 using namespace std;
     6 const int N=2e5+5;
     7 int n,m,x,y,ans,a[N],b[N],fail[N];
     8 int read()
     9 {
    10     int x=0,f=1;char c=getchar();
    11     while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    12     while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
    13     return x*f;
    14 }
    15 int main()
    16 {
    17     n=read()-1;m=read()-1;
    18     x=read();
    19     for(int i=1;i<=n;i++)y=read(),a[i]=y-x,x=y;
    20     x=read();
    21     for(int i=1;i<=m;i++)y=read(),b[i]=y-x,x=y;
    22     if(m==0){printf("%d",n+1);return 0;}
    23     if(n<m){printf("0");return 0;}
    24     int j=0;
    25     for(int i=2;i<=m;i++)
    26     {
    27         while(j&&b[j+1]!=b[i])j=fail[j];
    28         if(b[j+1]==b[i])j++;
    29         fail[i]=j;
    30     }
    31     j=0;
    32     for(int i=1;i<=n;i++)
    33     {
    34         while(j&&b[j+1]!=a[i])j=fail[j];
    35         if(b[j+1]==a[i])j++;
    36         if(j==m)ans++,j=fail[j];
    37     }
    38     printf("%d",ans);
    39     return 0;
    40 }
    View Code

    3.【bzoj3670】[Noi2014]动物园

    题意:求出一个num数组一一对于字符串S的前i个字符构成的子串,既是它的后缀同时又是它的前缀,并且该后缀与该前缀不重叠,将这种字符串的数量记作num[i]。输出Π(num[i]+1)。

    分析:num指的是数量而不是长度。

     1 #include<cstdio>
     2 #include<algorithm> 
     3 #include<cstring>
     4 #define LL long long
     5 using namespace std;
     6 const int N=1e6+5;
     7 const int mod=1e9+7;
     8 int T,n,ans,j,fail[N],num[N];
     9 char s[N];
    10 int read()
    11 {
    12     int x=0,f=1;char c=getchar();
    13     while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    14     while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
    15     return x*f;
    16 }
    17 int main()
    18 {
    19     T=read();
    20     while(T--)
    21     {
    22         scanf("%s",s+1);
    23         n=strlen(s+1);ans=1;
    24         num[1]=1;j=0;
    25         for(int i=2;i<=n;i++)
    26         {
    27             while(j&&s[j+1]!=s[i])j=fail[j];
    28             if(s[j+1]==s[i])j++;
    29             fail[i]=j;num[i]=num[j]+1;
    30         }
    31         j=0;
    32         for(int i=1;i<=n;i++)
    33         {
    34             while(j&&s[j+1]!=s[i])j=fail[j];
    35             if(s[j+1]==s[i])j++;
    36             while(j*2>i)j=fail[j];
    37             ans=1ll*ans*(num[j]+1)%mod;
    38         }
    39         printf("%d
    ",ans);
    40     }
    41     return 0;
    42 }
    View Code

    4.【bzoj1009】[HNOI2008]GT考试

    题意:阿申准备报名参加GT考试,准考证号为N位数X1X2....Xn(0<=Xi<=9),他不希望准考证号上出现不吉利的数字。他的不吉利数学A1A2...Am(0<=Ai<=9)有M位,不出现是指X1X2...Xn中没有恰好一段等于A1A2...Am。阿申想知道不出现不吉利数字的号码有多少种。

    分析:hzwerの博客

     1 #include<cstdio>
     2 #include<algorithm> 
     3 #include<cstring>
     4 #define LL long long
     5 using namespace std;
     6 const int N=25;
     7 int n,m,mod,j,ans,num[N],fail[N];
     8 char ch[N];
     9 struct node{int a[N][N];node(){memset(a,0,sizeof(a));}}a,b;
    10 int read()
    11 {
    12     int x=0,f=1;char c=getchar();
    13     while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    14     while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
    15     return x*f;
    16 }
    17 node operator * (node a,node b)
    18 {
    19     node c;
    20     for(int i=0;i<m;i++)
    21         for(int j=0;j<m;j++)
    22             for(int k=0;k<m;k++)
    23                 c.a[i][j]=(c.a[i][j]+a.a[i][k]*b.a[k][j]%mod)%mod;
    24     return c;
    25 }
    26 int main()
    27 {
    28     n=read();m=read();mod=read();scanf("%s",ch+1);
    29     for(int i=1;i<=m;i++)num[i]=ch[i]-'0';
    30     for(int i=0;i<m;i++)a.a[i][i]=1;
    31     for(int i=2;i<=m;i++)
    32     {
    33         while(j&&num[j+1]!=num[i])j=fail[j];
    34         if(num[j+1]==num[i])j++;
    35         fail[i]=j;
    36     }
    37     for(int i=0;i<m;i++)
    38         for(int j=0;j<=9;j++)
    39         {
    40             int t=i;
    41             while(t&&num[t+1]!=j)t=fail[t];
    42             if(num[t+1]==j)t++;
    43             if(t!=m)b.a[i][t]=(b.a[i][t]+1)%mod;
    44         }
    45     while(n)
    46     {
    47         if(n&1)a=a*b;
    48         b=b*b;n>>=1;
    49     }
    50     for(int i=0;i<m;i++)ans=(ans+a.a[0][i])%mod;
    51     printf("%d",ans);
    52     return 0;
    53 }
    View Code

    【后缀数组】

    〖模板代码

     1 void build()
     2 {
     3     int *x=t1,*y=t2;
     4     for(int i=0;i<n;i++)c[x[i]]++;
     5     for(int i=1;i<m;i++)c[i]+=c[i-1];
     6     for(int i=n-1;i>=0;i--)sa[--c[x[i]]]=i;
     7     for(int k=1;k<=n;k<<=1)
     8     {
     9         int p=0;
    10         for(int i=n-k;i<n;i++)y[p++]=i;
    11         for(int i=0;i<n;i++)if(sa[i]>=k)y[p++]=sa[i]-k;
    12         memset(c,0,sizeof(c));
    13         for(int i=0;i<n;i++)c[x[y[i]]]++;
    14         for(int i=1;i<m;i++)c[i]+=c[i-1];
    15         for(int i=n-1;i>=0;i--)sa[--c[x[y[i]]]]=y[i];
    16         swap(x,y);
    17         p=1;x[sa[0]]=0;
    18         for(int i=1;i<n;i++)
    19             x[sa[i]]=y[sa[i-1]]==y[sa[i]]&&y[sa[i-1]+k]==y[sa[i]+k]?p-1:p++;
    20         if(p>=n)break;
    21         m=p;
    22     }
    23 }
    View Code

    【AC自动机】

    〖相关资料

    AC自动机总结及板子(不带指针)

    〖模板代码

     1 struct Trie
     2 {
     3     int root,cnt;
     4     int son[N*55][26],fail[N*55],num[N*55];
     5     bool mark[N*55];
     6     void init()
     7     {
     8         cnt=1;root=0;
     9         memset(son,0,sizeof(son));
    10         memset(fail,0,sizeof(fail));
    11         memset(num,0,sizeof(num));
    12         memset(mark,0,sizeof(mark));
    13     }
    14     int idx(char c){return c-'a';}
    15     void ins(char s[])
    16     {
    17         int len=strlen(s),cur=root;
    18         for(int i=0;i<len;i++)
    19         {
    20             int id=idx(s[i]);
    21             if(!son[cur][id])son[cur][id]=cnt++;
    22             cur=son[cur][id];
    23         }
    24         num[cur]++;
    25     }
    26     void build()
    27     {
    28         int head=0,tail=0,q[N*55],now,nex;
    29         for(int i=0;i<26;i++)
    30         {
    31             now=son[root][i];
    32             if(now)q[tail++]=now;
    33         } 
    34         while(head!=tail)
    35         {
    36             now=q[head++];
    37             for(int i=0;i<26;i++)
    38             {
    39                 nex=son[now][i];
    40                 if(!nex){son[now][i]=son[fail[now]][i];continue;}
    41                 q[tail++]=nex;
    42                 fail[nex]=son[fail[now]][i];
    43             }
    44         }
    45     }
    46     void query(char s[])
    47     {
    48         int len=strlen(s),j=root,c;
    49         for(int i=0;i<len;i++)
    50         {
    51             mark[j]=true;c=idx(s[i]);
    52             while(j&&!son[j][c])j=fail[j];
    53             j=son[j][c];
    54             if(!mark[j])
    55                 for(int tmp=j;tmp;tmp=fail[tmp])
    56                     ans+=num[tmp],num[tmp]=0;
    57         }
    58         printf("%d
    ",ans);
    59     }
    60 }AC;
    View Code

    〖相关题目

    1.【hdu2222】Keywords Search

    题意:给出n个单词和1个模式串,求有多少个单词在模式串中出现。

    分析:AC自动机裸题

     1 #include<cstdio>
     2 #include<algorithm> 
     3 #include<cstring>
     4 #define LL long long
     5 using namespace std;
     6 const int N=1e4+5;
     7 int T,n,ans;
     8 char s[N][55],ss[N*100];
     9 struct Trie
    10 {
    11     int root,cnt;
    12     int son[N*55][26],fail[N*55],num[N*55];
    13     bool mark[N*55];
    14     void init()
    15     {
    16         cnt=1;root=0;
    17         memset(son,0,sizeof(son));
    18         memset(fail,0,sizeof(fail));
    19         memset(num,0,sizeof(num));
    20         memset(mark,0,sizeof(mark));
    21     }
    22     int idx(char c){return c-'a';}
    23     void ins(char s[])
    24     {
    25         int len=strlen(s),cur=root;
    26         for(int i=0;i<len;i++)
    27         {
    28             int id=idx(s[i]);
    29             if(!son[cur][id])son[cur][id]=cnt++;
    30             cur=son[cur][id];
    31         }
    32         num[cur]++;
    33     }
    34     void build()
    35     {
    36         int head=0,tail=0,q[N*55],now,nex;
    37         for(int i=0;i<26;i++)
    38         {
    39             now=son[root][i];
    40             if(now)q[tail++]=now;
    41         } 
    42         while(head!=tail)
    43         {
    44             now=q[head++];
    45             for(int i=0;i<26;i++)
    46             {
    47                 nex=son[now][i];
    48                 if(!nex){son[now][i]=son[fail[now]][i];continue;}
    49                 q[tail++]=nex;
    50                 fail[nex]=son[fail[now]][i];
    51             }
    52         }
    53     }
    54     void query(char s[])
    55     {
    56         int len=strlen(s),j=root,c;
    57         for(int i=0;i<len;i++)
    58         {
    59             mark[j]=true;c=idx(s[i]);
    60             while(j&&!son[j][c])j=fail[j];
    61             j=son[j][c];
    62             if(!mark[j])
    63                 for(int tmp=j;tmp;tmp=fail[tmp])
    64                     ans+=num[tmp],num[tmp]=0;
    65         }
    66         printf("%d
    ",ans);
    67     }
    68 }AC;
    69 void work()
    70 {
    71     scanf("%d",&n);AC.init();ans=0;
    72     for(int i=1;i<=n;i++)scanf("%s",s[i]),AC.ins(s[i]);
    73     AC.build();scanf("%s",ss);AC.query(ss);
    74 }
    75 int main()
    76 {
    77     scanf("%d",&T);
    78     while(T--)work();
    79     return 0;
    80 }
    View Code

    2.【hdu2896】病毒侵袭

    题意:给出n个单词和m个模式串,输出在每个模式串中出现的单词编号。

    分析:AC自动机裸题

     1 #include<cstdio>
     2 #include<cstring>
     3 #include<algorithm>
     4 using namespace std;
     5 const int N=1e5+5;
     6 const int M=1e4+5;
     7 int n,m,ans,id[505];
     8 bool mark[N];
     9 char s[M];
    10 struct Trie
    11 {
    12     int cnt,son[N][128],fail[N],num[N],q[N];
    13     void ins(int v)
    14     {
    15         int cur=0,len=strlen(s);
    16         for(int i=0;i<len;i++)
    17         {
    18             int now=s[i];
    19             if(!son[cur][now])son[cur][now]=cnt++;
    20             cur=son[cur][now];
    21         }
    22         num[cur]++;id[v]=cur;
    23     }
    24     void build()
    25     {
    26         int head=0,tail=0,now,nex;
    27         for(int i=0;i<128;i++)
    28         {
    29             now=son[0][i];
    30             if(now)q[tail++]=now;
    31         }
    32         while(head!=tail)
    33         {
    34             now=q[head++];
    35             for(int i=0;i<128;i++)
    36             {
    37                 nex=son[now][i];
    38                 if(!nex){son[now][i]=son[fail[now]][i];continue;}
    39                 q[tail++]=nex;
    40                 fail[nex]=son[fail[now]][i];
    41             }
    42         }
    43     }
    44     void query(int v)
    45     {
    46         int len=strlen(s),j=0,c;
    47         bool flag=false;
    48         memset(mark,0,sizeof(mark));
    49         for(int i=0;i<len;i++)
    50         {
    51             c=s[i];j=son[j][c];
    52             for(int tmp=j;tmp;tmp=fail[tmp])
    53                 if(num[tmp])flag=true,mark[tmp]=true;
    54         }
    55         if(!flag)return;
    56         printf("web %d:",v);
    57         for(int i=1;i<=n;i++)
    58             if(mark[id[i]])printf(" %d",i);
    59         printf("
    ");ans++;
    60     }
    61 }AC;
    62 int main()
    63 {
    64     AC.cnt=1;
    65     scanf("%d",&n);
    66     for(int i=1;i<=n;i++)scanf("%s",s),AC.ins(i);
    67     AC.build();
    68     scanf("%d",&m);
    69     for(int i=1;i<=m;i++)scanf("%s",s),AC.query(i);
    70     printf("total: %d",ans);
    71     return 0;
    72 }
    View Code

    3.【hdu3065】病毒侵袭持续中

    题意:给出n个单词和1个模式串,求每个单词在模式串中出现的次数。

    分析:AC自动机裸题

     1 #include<cstdio>
     2 #include<algorithm> 
     3 #include<cstring>
     4 #define LL long long
     5 using namespace std;
     6 const int N=1e3+5;
     7 const int M=5e4+5;
     8 const int L=2e6+5;
     9 int n,times[N];
    10 char s[N][55],ch[L];
    11 struct Trie
    12 {
    13     int cnt,son[M][27],fail[M],num[M],q[M];
    14     void init()
    15     {
    16         cnt=1;
    17         memset(son,0,sizeof(son));
    18         memset(fail,0,sizeof(fail));
    19         memset(num,0,sizeof(num));
    20     }
    21     int idx(char c)
    22     {
    23         if(c>='A'&&c<='Z')return c-'A';
    24         return 26;
    25     }
    26     void ins(int v)
    27     {
    28         int cur=0,len=strlen(s[v]);
    29         for(int i=0;i<len;i++)
    30         {
    31             int now=idx(s[v][i]);
    32             if(!son[cur][now])son[cur][now]=cnt++;
    33             cur=son[cur][now];
    34         }
    35         num[cur]=v;
    36     }
    37     void build()
    38     {
    39         int head=0,tail=0,now,nex;
    40         for(int i=0;i<=26;i++)
    41         {
    42             now=son[0][i];
    43             if(now)q[tail++]=now;
    44         }
    45         while(head!=tail)
    46         {
    47             now=q[head++];
    48             for(int i=0;i<=26;i++)
    49             {
    50                 nex=son[now][i];
    51                 if(!nex){son[now][i]=son[fail[now]][i];continue;}
    52                 q[tail++]=nex;
    53                 fail[nex]=son[fail[now]][i];
    54             }
    55         }
    56     }
    57     void query()
    58     {
    59         int len=strlen(ch),j=0,c;
    60         for(int i=0;i<len;i++)
    61         {
    62             c=idx(ch[i]);j=son[j][c];
    63             for(int tmp=j;tmp;tmp=fail[tmp])
    64                 if(num[tmp])times[num[tmp]]++;
    65         }
    66         for(int i=1;i<=n;i++)
    67             if(times[i])printf("%s: %d
    ",s[i],times[i]);
    68     }
    69 }AC;
    70 int main()
    71 {
    72     while(scanf("%d",&n)==1)
    73     {
    74         memset(times,0,sizeof(times));
    75         AC.init();
    76         for(int i=1;i<=n;i++)scanf("%s",s[i]),AC.ins(i);
    77         AC.build();scanf("%s",ch);AC.query();
    78     }
    79     return 0;
    80 }
    View Code

    4.【bzoj2938】病毒

    题意:已知某些确定的01串是病毒代码。如果某段代码中不存在任何一段病毒代码,那么我们就称这段代码是安全的。已知所有的病毒代码段,试问,是否存在一个无限长的安全的二进制代码。

    分析:hzwerの博客

     1 #include<cstdio>
     2 #include<cstring>
     3 #include<algorithm>
     4 using namespace std;
     5 const int N=3e4+5;
     6 int n;
     7 char s[N];
     8 struct Trie
     9 {
    10     int cnt,son[N][2],fail[N],q[N];
    11     bool ed[N],in[N],vis[N];
    12     int idx(char c){return c-'0';}
    13     void ins()
    14     {
    15         scanf("%s",s);
    16         int cur=0,len=strlen(s);
    17         for(int i=0;i<len;i++)
    18         {
    19             int now=idx(s[i]);
    20             if(!son[cur][now])son[cur][now]=cnt++;
    21             cur=son[cur][now];
    22         }
    23         ed[cur]=true;
    24     }
    25     void build()
    26     {
    27         int head=0,tail=0,now,nex;
    28         for(int i=0;i<2;i++)
    29         {
    30             now=son[0][i];
    31             if(now)q[tail++]=now;
    32         }
    33         while(head!=tail)
    34         {
    35             now=q[head++];
    36             for(int i=0;i<2;i++)
    37             {
    38                 nex=son[now][i];
    39                 if(!nex){son[now][i]=son[fail[now]][i];continue;}
    40                 q[tail++]=nex;
    41                 fail[nex]=son[fail[now]][i];
    42                 ed[nex]|=ed[fail[nex]];
    43             }
    44         }
    45     }
    46     bool dfs(int x)
    47     {
    48         in[x]=true;
    49         for(int i=0;i<2;i++)
    50         {
    51             int now=son[x][i];
    52             if(in[now])return true;
    53             if(ed[now]||vis[now])continue;
    54             vis[now]=true;
    55             if(dfs(now))return true;
    56         }
    57         in[x]=false;
    58         return false;
    59     }
    60 }AC;
    61 int main()
    62 {
    63     AC.cnt=1;
    64     scanf("%d",&n);
    65     for(int i=1;i<=n;i++)AC.ins();
    66     AC.build();
    67     if(AC.dfs(0))printf("TAK
    ");
    68     else printf("NIE
    ");
    69     return 0;
    70 }
    View Code

    【后缀自动机】

    〖注意事项

    实现后缀排序时,记得t[nq].id=0。

    〖模板代码

    [普通SAM]

     1 struct SAM{int mx,fa,ch[26];}t[N<<1];
     2 void ins(int c)
     3 {
     4     int np=++size;
     5     t[np].mx=t[last].mx+1;
     6     int x=last;last=np;
     7     while(x&&!t[x].ch[c])t[x].ch[c]=np,x=t[x].fa;
     8     if(!x)t[np].fa=root;
     9     else
    10     {
    11         int y=t[x].ch[c];
    12         if(t[y].mx==t[x].mx+1)t[np].fa=y;
    13         else
    14         {
    15             int nq=++size;
    16             t[nq]=t[y];
    17             t[nq].mx=t[x].mx+1;
    18             t[y].fa=t[np].fa=nq;
    19             while(x&&t[x].ch[c]==y)t[x].ch[c]=nq,x=t[x].fa;
    20         }
    21     }
    22 }
    23 int main()
    24 {
    25     scanf("%s",s+1);n=strlen(s+1);
    26     last=size=root=1;
    27     for(int i=1;i<=n;i++)ins(s[i]-'a');
    28     return 0;
    29 }
    View Code

    [后缀排序]

     1 #include<cstdio>
     2 #include<algorithm> 
     3 #include<cstring>
     4 #include<cmath>
     5 #define LL long long
     6 using namespace std;
     7 const int N=15005;
     8 int n,size,root,last,tot,cnt,scnt;
     9 int c[26],sa[N],first[N<<1],rk[N<<1];
    10 char ch[N]; 
    11 bool vis[N<<1];
    12 struct sam{int mx,fa,id,ch[26];}t[N<<1];
    13 struct node{int x,y,v;}a[N<<1];
    14 struct edge{int to,next;}e[N<<1];
    15 void insert(int u,int v){e[++cnt]=(edge){v,first[u]};first[u]=cnt;}
    16 void ins(int c,int pos)
    17 {
    18     int np=++size;
    19     t[np].mx=t[last].mx+1;
    20     t[np].id=pos;
    21     int x=last;last=np;
    22     while(x&&!t[x].ch[c])t[x].ch[c]=np,x=t[x].fa;
    23     if(!x)t[np].fa=root;
    24     else
    25     {
    26         int y=t[x].ch[c];
    27         if(t[y].mx==t[x].mx+1)t[np].fa=y;
    28         else
    29         {
    30             int nq=++size;t[nq]=t[y];
    31             t[nq].mx=t[x].mx+1;t[nq].id=0;
    32             t[y].fa=t[np].fa=nq;
    33             while(x&&t[x].ch[c]==y)t[x].ch[c]=nq,x=t[x].fa;
    34         }
    35     }
    36 }
    37 void dfs(int x)
    38 {
    39     if(t[x].id)sa[++scnt]=t[x].id;
    40     for(int i=first[x];i;i=e[i].next)dfs(e[i].to);
    41 }
    42 int main()
    43 {
    44     scanf("%d%s",&n,ch+1);
    45     size=root=last=1;vis[1]=true;
    46     for(int i=n;i>=1;i--)ins(ch[i]-'a',i);
    47     for(int i=1;i<=size;i++)
    48         if(!vis[i]&&t[i].id)
    49             for(int pos=n,j=i;!vis[j];vis[j]=true,j=t[j].fa,--pos)
    50             {
    51                 pos=pos-t[j].mx+t[t[j].fa].mx+1;
    52                 a[++tot]=(node){t[j].fa,j,ch[pos]-'a'};
    53             }
    54     for(int i=1;i<=tot;i++)c[a[i].v]++;
    55     for(int i=1;i<26;i++)c[i]+=c[i-1];
    56     for(int i=1;i<=tot;i++)rk[c[a[i].v]--]=i;
    57     for(int i=tot;i>=1;i--)insert(a[rk[i]].x,a[rk[i]].y);
    58     dfs(1);
    59     for(int i=1;i<=n;i++)printf("%d
    ",sa[i]);
    60     return 0;
    61 }
    View Code

    〖相关题目

    1.【Luogu P3804】【模板】后缀自动机

    题意:给定一个只包含小写字母的字符串SS,请你求出 SS 的所有出现次数不为 11 的子串的出现次数乘上该子串长度的最大值。

    分析:后缀自动机裸题

     1 #include<cstdio>
     2 #include<algorithm>
     3 #include<cstring>
     4 #define LL long long
     5 using namespace std;
     6 const int N=1e6+5;
     7 int n,last,size,root,x;
     8 int sz[N<<1],c[N<<1],q[N<<1];
     9 LL ans;
    10 char s[N];
    11 struct SAM{int mx,fa,ch[26];}t[N<<1];
    12 void ins(int c)
    13 {
    14     int np=++size;sz[np]=1;
    15     t[np].mx=t[last].mx+1;
    16     int x=last;last=np;
    17     while(x&&!t[x].ch[c])t[x].ch[c]=np,x=t[x].fa;
    18     if(!x)t[np].fa=root;
    19     else
    20     {
    21         int y=t[x].ch[c];
    22         if(t[y].mx==t[x].mx+1)t[np].fa=y;
    23         else
    24         {
    25             int nq=++size;
    26             t[nq]=t[y];
    27             t[nq].mx=t[x].mx+1;
    28             t[nq].fa=t[y].fa;
    29             t[y].fa=t[np].fa=nq;
    30             while(x&&t[x].ch[c]==y)t[x].ch[c]=nq,x=t[x].fa;
    31         }
    32     }
    33 }
    34 int main()
    35 {
    36     scanf("%s",s+1);n=strlen(s+1);
    37     last=size=root=1;
    38     for(int i=1;i<=n;i++)ins(s[i]-'a');
    39     for(int i=1;i<=size;i++)c[t[i].mx]++;
    40     for(int i=1;i<=size;i++)c[i]+=c[i-1];
    41     for(int i=1;i<=size;i++)q[c[t[i].mx]--]=i;
    42     for(int i=size;i>=1;i--)
    43     {
    44         x=q[i];sz[t[x].fa]+=sz[x];
    45         if(sz[x]>1)ans=max(ans,1ll*sz[x]*t[x].mx);
    46     }
    47     printf("%lld",ans);
    48     return 0;
    49 }
    View Code

    2.【bzoj3238】[Ahoi2013]差异

    题意:给定长度为n的小写字母字符串,令Ti表示以i开头的后缀,求Σ[Ti+Tj-2*lcp(Ti,Tj)],1<=i<j<=n。

    分析:把串倒过来,两个后缀的lcp就是他们在Parent树上的LCA

     1 #include<cstdio>
     2 #include<algorithm>
     3 #include<cstring>
     4 #define LL long long
     5 using namespace std;
     6 const int N=1e6+5;
     7 int n,size,last,root,cnt;
     8 int first[N],sz[N];
     9 LL ans;
    10 bool f[N];
    11 char s[N];
    12 struct SAM{int mx,fa,ch[26];}t[N];
    13 struct edge{int to,next;}e[N];
    14 void insert(int u,int v){e[++cnt]=(edge){v,first[u]};first[u]=cnt;}
    15 void ins(int c)
    16 {
    17     int np=++size;f[np]=true;
    18     t[np].mx=t[last].mx+1;
    19     int x=last;last=np;
    20     while(x&&!t[x].ch[c])t[x].ch[c]=np,x=t[x].fa;
    21     if(!x)t[np].fa=root;
    22     else
    23     {
    24         int y=t[x].ch[c];
    25         if(t[y].mx==t[x].mx+1)t[np].fa=y;
    26         else
    27         {
    28             int nq=++size;
    29             t[nq]=t[y];
    30             t[nq].mx=t[x].mx+1;
    31             t[y].fa=t[np].fa=nq;
    32             while(x&&t[x].ch[c]==y)t[x].ch[c]=nq,x=t[x].fa;
    33         }
    34     }
    35 }
    36 void dfs(int x)
    37 {
    38     sz[x]=f[x]?1:0;
    39     for(int i=first[x];i;i=e[i].next)
    40     {
    41         int to=e[i].to;dfs(to);
    42         ans+=1ll*t[x].mx*sz[x]*sz[to];
    43         sz[x]+=sz[to];
    44     }
    45 }
    46 int main()
    47 {
    48     scanf("%s",s+1);n=strlen(s+1);
    49     last=size=root=1;
    50     for(int i=n;i>=1;i--)ins(s[i]-'a');
    51     for(int i=2;i<=size;i++)insert(t[i].fa,i);
    52     dfs(1);printf("%lld",1ll*(n+1)*n/2*(n-1)-2*ans);
    53     return 0;
    54 }
    View Code

    3.【bzoj4032】[HEOI2015]最短不公共子串

    题意:给两个小写字母串A,B,计算:(1) A的一个最短的子串,它不是B的子串;(2) A的一个最短的子串,它不是B的子序列;(3) A的一个最短的子序列,它不是B的子串;(4) A的一个最短的子序列,它不是B的子序列。

    分析:后缀自动机+序列自动机

      1 #include<cstdio>
      2 #include<algorithm>
      3 #include<cstring>
      4 #define LL long long
      5 using namespace std;
      6 const int N=2005;
      7 const int inf=0x3f3f3f3f;
      8 int n,m,c,x,y,root,size,last,ans,now,sum;
      9 int pre[26],nexa[N][26],nexb[N][26],f[N][N<<1];
     10 char a[N],b[N];
     11 struct SAM{int mx,fa,ch[26];}t[N<<1];
     12 void insert(int c)
     13 {
     14     int np=++size;
     15     t[np].mx=t[last].mx+1;
     16     int x=last;last=np;
     17     while(x&&!t[x].ch[c])t[x].ch[c]=np,x=t[x].fa;
     18     if(!x)t[np].fa=root;
     19     else
     20     {
     21         int y=t[x].ch[c];
     22         if(t[y].mx==t[x].mx+1)t[np].fa=y;
     23         else
     24         {
     25             int nq=++size;t[nq]=t[y];
     26             t[nq].mx=t[x].mx+1;
     27             t[y].fa=t[np].fa=nq;
     28             while(x&&t[x].ch[c]==y)t[x].ch[c]=nq,x=t[x].fa;
     29         }
     30     }
     31 }
     32 void work1()
     33 {
     34     ans=n+1;
     35     for(int i=1;i<=n;i++)
     36     {
     37         now=root;sum=0;c=a[i+sum]-'a';
     38         while(i+sum<=n&&t[now].ch[c])
     39         {
     40             now=t[now].ch[c];sum++;
     41             c=a[i+sum]-'a';
     42         }
     43         if(i+sum!=n+1)ans=min(ans,sum+1);
     44     }
     45     if(ans==n+1)printf("-1
    ");
     46     else printf("%d
    ",ans);
     47 }
     48 void work2()
     49 {
     50     ans=n+1;
     51     for(int i=1;i<=n;i++)
     52     {
     53         now=0;sum=0;c=a[i+sum]-'a';
     54         while(i+sum<=n&&nexb[now][c])
     55         {
     56             now=nexb[now][c];sum++;
     57             c=a[i+sum]-'a';
     58         }
     59         if(i+sum!=n+1)ans=min(ans,sum+1);
     60     }
     61     if(ans==n+1)printf("-1
    ");
     62     else printf("%d
    ",ans);
     63 }
     64 void work3()
     65 {
     66     memset(f,0x3f,sizeof(f));
     67     f[0][1]=0;ans=n+1;
     68     for(int i=0;i<n;i++)
     69         for(int j=1;j<=size;j++)
     70         {
     71             if(f[i][j]==inf)continue;
     72             for(int k=0;k<26;k++)
     73                 if(x=nexa[i][k])
     74                 {
     75                     y=t[j].ch[k];
     76                     if(!y)ans=min(ans,f[i][j]+1);
     77                     else f[x][y]=min(f[x][y],f[i][j]+1);
     78                 }
     79         }
     80     if(ans==n+1)printf("-1
    ");
     81     else printf("%d
    ",ans);
     82 }
     83 void work4()
     84 {
     85     memset(f,0x3f,sizeof(f));
     86     f[0][0]=0;ans=n+1;
     87     for(int i=0;i<n;i++)
     88         for(int j=0;j<=m;j++)
     89         {
     90             if(f[i][j]==inf)continue;
     91             for(int k=0;k<26;k++)
     92                 if(x=nexa[i][k])
     93                 {
     94                     y=nexb[j][k];
     95                     if(!y)ans=min(ans,f[i][j]+1);
     96                     else f[x][y]=min(f[x][y],f[i][j]+1);
     97                 }
     98         }
     99     if(ans==n+1)printf("-1
    ");
    100     else printf("%d
    ",ans);
    101 }
    102 int main()
    103 {
    104     scanf("%s%s",a+1,b+1);
    105     n=strlen(a+1);m=strlen(b+1);
    106     last=root=size=1;
    107     for(int i=1;i<=m;i++)insert(b[i]-'a');
    108     for(int i=1;i<=n;i++)
    109     {
    110         c=a[i]-'a';
    111         for(int j=i-1;j>=pre[c];j--)nexa[j][c]=i;
    112         pre[c]=i;
    113     }
    114     memset(pre,0,sizeof(pre));
    115     for(int i=1;i<=m;i++)
    116     {
    117         c=b[i]-'a';
    118         for(int j=i-1;j>=pre[c];j--)nexb[j][c]=i;
    119         pre[c]=i;
    120     }
    121     work1();work2();work3();work4();
    122     return 0;
    123 }
    View Code

    4.【bzoj3998】[TJOI2015]弦论

    题意:对于一个给定长度为N的字符串,求它的第K小子串是什么。

    分析:hzwerの博客

     1 #include<cstdio>
     2 #include<algorithm>
     3 #include<cstring>
     4 #define LL long long
     5 using namespace std;
     6 const int N=5e5+5;
     7 int n,root,last,size,T,K,x;
     8 int c[N<<1],val[N<<1],q[N<<1],sum[N<<1];
     9 char s[N];
    10 struct SAM{int mx,fa,ch[26];}t[N<<1];
    11 void insert(int c)
    12 {
    13     int np=++size;val[np]=1;
    14     t[np].mx=t[last].mx+1;
    15     int x=last;last=np;
    16     while(x&&!t[x].ch[c])t[x].ch[c]=np,x=t[x].fa;
    17     if(!x)t[np].fa=root;
    18     else
    19     {
    20         int y=t[x].ch[c];
    21         if(t[y].mx==t[x].mx+1)t[np].fa=y;
    22         else
    23         {
    24             int nq=++size;
    25             t[nq]=t[y];
    26             t[nq].mx=t[x].mx+1;
    27             t[y].fa=t[np].fa=nq;
    28             while(x&&t[x].ch[c]==y)t[x].ch[c]=nq,x=t[x].fa;
    29         }
    30     }
    31 }
    32 void dfs(int now,int K)
    33 {
    34     if(K<=val[now])return;
    35     K-=val[now];
    36     for(int i=0;i<26;i++)
    37     {
    38         x=t[now].ch[i];
    39         if(!x)continue;
    40         if(K<=sum[x]){putchar(i+'a');dfs(x,K);return;}
    41         K-=sum[x];
    42     }
    43 }
    44 int main()
    45 {
    46     scanf("%s%d%d",s+1,&T,&K);
    47     n=strlen(s+1);root=last=size=1;
    48     for(int i=1;i<=n;i++)insert(s[i]-'a');
    49     for(int i=1;i<=size;i++)c[t[i].mx]++;
    50     for(int i=1;i<=size;i++)c[i]+=c[i-1];
    51     for(int i=1;i<=size;i++)q[c[t[i].mx]--]=i;
    52     for(int i=size;i>=1;i--)
    53     {
    54         x=q[i];
    55         if(T==1)val[t[x].fa]+=val[x];
    56         else val[x]=1;
    57     }
    58     val[1]=0;
    59     for(int i=size;i>=1;i--)
    60     {
    61         x=q[i];sum[x]=val[x];
    62         for(int j=0;j<26;j++)sum[x]+=sum[t[x].ch[j]];
    63     }
    64     if(K>sum[root]){printf("-1
    ");return 0;}
    65     dfs(root,K);
    66     return 0;
    67 }
    View Code

    5.【bzoj2780】[Spoj]8093 Sevenk Love Oimaster

    题意:给你n个文本串,m个询问串,询问每个串在多少个文本串中出现过。

    分析:广义后缀自动机。

     1 #include<cstdio>
     2 #include<algorithm>
     3 #include<cstring>
     4 #define LL long long
     5 using namespace std;
     6 const int N=1e4+5;
     7 const int M=1e5+5;
     8 int n,m,last,root,size,now,len,tmp;
     9 int L[N],R[N],vis[M<<1],sz[M<<1];
    10 char str[M];
    11 struct SAM{int fa,mx,ch[26];}t[M<<1];
    12 void insert(int c)
    13 {
    14     int np=++size;
    15     t[np].mx=t[last].mx+1;
    16     int x=last;last=np;
    17     while(x&&!t[x].ch[c])t[x].ch[c]=np,x=t[x].fa;
    18     if(!x)t[np].fa=root;
    19     else
    20     {
    21         int y=t[x].ch[c];
    22         if(t[y].mx==t[x].mx+1)t[np].fa=y;
    23         else
    24         {
    25             int nq=++size;
    26             t[nq]=t[y];
    27             t[nq].mx=t[x].mx+1;
    28             t[y].fa=t[np].fa=nq;
    29             while(x&&t[x].ch[c]==y)t[x].ch[c]=nq,x=t[x].fa;
    30         }
    31     }
    32 }
    33 void up(int x,int id)
    34 {
    35     while(x&&vis[x]!=id)
    36     {
    37         sz[x]++;vis[x]=id;
    38         x=t[x].fa;
    39     }
    40 }
    41 int main()
    42 {
    43     last=root=size=1;
    44     scanf("%d%d",&n,&m);
    45     for(int i=1;i<=n;i++)
    46     {
    47         L[i]=R[i-1];scanf("%s",str+L[i]);
    48         R[i]=strlen(str);last=1;
    49         for(int j=L[i];j<R[i];j++)insert(str[j]-'a');
    50     }
    51     for(int i=1;i<=n;i++)
    52     {
    53         now=1;
    54         for(int j=L[i];j<R[i];j++)
    55             now=t[now].ch[str[j]-'a'],up(now,i);
    56     }
    57     int i;
    58     while(m--)
    59     {
    60         scanf("%s",str);
    61         len=strlen(str);now=1;
    62         for(i=0;i<len;i++)
    63         {
    64             tmp=t[now].ch[str[i]-'a'];
    65             if(!tmp)break;now=tmp;
    66         }
    67         if(i==len)printf("%d
    ",sz[now]);
    68         else printf("0
    ");
    69     }
    70     return 0;
    71 }
    View Code

    【序列自动机】

    〖模板代码

    1 for(int i=1;i<=n;i++)
    2 {
    3     c=s[i]-'a';
    4     for(int j=i-1;j>=pre[c];j--)nex[j][c]=i;
    5     pre[c]=i;
    6 }
    View Code

    【Manacher】

    〖模板代码

     1 #include<cstdio>
     2 #include<algorithm> 
     3 #include<cstring>
     4 #include<cmath>
     5 #define LL long long
     6 using namespace std;
     7 const int N=2e7+2e6+5;
     8 int n,len,ans,p[N];
     9 char ch[N],s[N];
    10 int main()
    11 {
    12     scanf("%s",ch+1);
    13     len=strlen(ch+1);
    14     s[0]='!';s[1]='#';n=1;
    15     for(int i=1;i<=len;i++)
    16         s[++n]=ch[i],s[++n]='#';
    17     int mxr=0,id=0;
    18     for(int i=1;i<=n;i++)
    19     {
    20         if(i<mxr)p[i]=min(p[2*id-i],mxr-i);
    21         else p[i]=1;
    22         for(;i+p[i]<=n&&s[i-p[i]]==s[i+p[i]];p[i]++);
    23         if(i+p[i]>mxr)mxr=i+p[i],id=i;
    24         ans=max(ans,p[i]-1);
    25     }
    26     printf("%d",ans);
    27     return 0;
    28 }
    View Code

    〖相关题目

    1.【bzoj2342】[Shoi2011]双倍回文

    题意:见原题

    分析:hzwerの博客

     1 #include<algorithm>
     2 #include<cmath>
     3 #include<cstdio>
     4 #include<cstring>
     5 #include<set>
     6 #define LL long long
     7 using namespace std;
     8 const int N=1e6+5;
     9 int len,n,ans,p[N],f[N]; 
    10 char ch[N],s[N];
    11 set<int>bt;
    12 struct node{int x,id;}a[N];
    13 bool cmp(node a,node b){return a.x<b.x;}
    14 void manacher()
    15 {
    16     int mxr=0,id=0;
    17     for(int i=1;i<=n;i++)
    18     {
    19         if(i<mxr)p[i]=min(p[2*id-i],mxr-i);else p[i]=1;
    20         for(;i+p[i]<=n&&s[i-p[i]]==s[i+p[i]];p[i]++);
    21         if(i+p[i]>mxr)mxr=i+p[i],id=i;
    22     }
    23 }
    24 int main()
    25 {
    26     scanf("%d%s",&len,ch+1);
    27     s[0]='!';s[1]='#';n=1;
    28     for(int i=1;i<=len;i++)s[++n]=ch[i],s[++n]='#';
    29     manacher();
    30     for(int i=1;i<=len;i++)f[i]=p[(i<<1)|1]-1,f[i]>>=1;
    31     for(int i=1;i<=len;i++)a[i].id=i,a[i].x=i-f[i];
    32     sort(a+1,a+len+1,cmp);
    33     int id=0;
    34     for(int i=1;i<=len;i++)
    35     {
    36          while(id+1<=n&&a[id+1].x<=i)id++,bt.insert(a[id].id);
    37          set<int>::iterator now=bt.upper_bound(i+f[i]/2);
    38          if(now!=bt.begin())ans=max(ans,((*--now)-i)*4);
    39     }
    40     printf("%d
    ",ans);
    41     return 0;
    42 }
    View Code
  • 相关阅读:
    C#中的Json序列化
    c#在sqlserver中使用EF框架
    Mvc中模拟模型
    localdb启动
    List泛型用法(半转载半原创)
    C#中真正的属性
    委托的简介、使用和简单事件
    类嵌套_list泛型_餐馆点菜例
    JavaIO
    JavaIO
  • 原文地址:https://www.cnblogs.com/zsnuo/p/8240923.html
Copyright © 2020-2023  润新知