zoukankan      html  css  js  c++  java
  • 【算法总结】字符串相关

    【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
  • 相关阅读:
    fn project 试用之后的几个问题的解答
    fn project 扩展
    fn project 生产环境使用
    fn project 对象模型
    fn project AWS Lambda 格式 functions
    fn project 打包Function
    fn project Function files 说明
    fn project hot functions 说明
    fn project k8s 集成
    fn project 私有镜像发布
  • 原文地址:https://www.cnblogs.com/zsnuo/p/8240923.html
Copyright © 2011-2022 走看看