zoukankan      html  css  js  c++  java
  • 字符串的模板 Manacher kmp ac自动机 后缀数组 后缀自动机

    为何scanf("%s", str)不需要&运算 经常忘掉的字符串知识点,最好不加&,不加&最标准,指针如果像scanf里一样加&是错的,大概是未定义行为

    马拉车

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<algorithm>
     4 #include<cstring>
     5 #include<cmath>
     6 #include<queue>
     7 using namespace std;
     8 const int maxn=100100;
     9 int n,siz;
    10 char ch[maxn]={};
    11 char ch1[maxn*2]={};
    12 int p[maxn*2]={};
    13 void fir(){
    14     siz=n*2+2;
    15     ch1[0]='$';ch1[1]='#';
    16     for(int i=1;i<=n;i++)ch1[i*2]=ch[i-1],ch1[i*2+1]='#';
    17     ch1[siz]='';
    18 }
    19 int Manacher(){
    20     fir();int x=0,j=0,ans=0;
    21     for(int i=1;i<siz;i++){
    22         if(x+j>i)p[i]=min(x+j-i+1,p[x*2-i]);
    23         else p[i]=0;
    24         while(ch1[i+p[i]]==ch1[i-p[i]])p[i]++;
    25         if(i+p[i]-1>x+j)x=i,j=p[i]-1;
    26         if(p[i]>ans)ans=p[i];
    27         //cout<<i<<ch1[i]<<p[i]<<endl;
    28     }
    29     return ans-1;
    30 }
    31 int main(){
    32     int T;scanf("%d",&T);
    33     while(T-->0){//ch[i],ch1[i],p[i]似乎都不用清空,因为所有的用之前都已经被清一次了。
    34         scanf("%s",ch);n=strlen(ch);
    35         int ma=Manacher();
    36         printf("%d
    ",ma);
    37     }
    38     return 0;
    39 }
    Manacher

     kmp

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<algorithm>
     4 #include<cstring>
     5 #include<cmath>
     6 #include<queue>
     7 using namespace std;
     8 const int maxn=100100;
     9 int cn,sn;//模式串和主串的大小
    10 char ch[maxn]={};//模式串
    11 char st[maxn]={};//主串
    12 int nex[maxn]={};
    13 void kmp(){
    14     int j=-1,i=0;
    15     nex[0]=-1;
    16     while(i<cn){
    17         if(j==-1||ch[i]==ch[j])nex[++i]=++j;
    18         else j=nex[j];
    19     }
    20 }
    21 int get_id(){//在主串中第一次出现的位置
    22     int i=0,j=0;
    23     while(i<sn&&j<cn){
    24         if(j==-1||ch[j]==st[i]){i++;j++;}
    25         else j=nex[j];
    26     }
    27     if(j==cn)return i-cn;
    28     else return -1;
    29 }
    30 int get_count(){//在主串中出现的次数
    31     int i,j=0,cnt=0;
    32     for(i=0;i<sn;i++){
    33         while(j>0&&st[i]!=ch[j]) j=nex[j];
    34         if(st[i]==ch[j])j++;
    35         if(j==cn){cnt++;j=nex[j];}
    36     }
    37     return cnt;
    38 }
    39 int main(){
    40     int T;scanf("%d",&T);
    41     while(T-->0){
    42         scanf("%s",ch);cn=strlen(ch);
    43         scanf("%s",st);sn=strlen(st);
    44         kmp();
    45         printf("%d %d
    ",get_id(),get_count());
    46     }
    47     return 0;
    48 }
    kmp

    ac自动机(在poj2222提交的时候wa了好几次后来发现没有清空,而且这次重新打发现了自己之前写的漏洞。。。)

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<algorithm>
     4 #include<cstring>
     5 #include<cmath>
     6 #include<queue>
     7 using namespace std;
     8 const int maxn=10100;
     9 int n,siz;
    10 char ch[60]={};
    11 char str[maxn*100]={};
    12 struct trie{
    13     int sig[26];
    14     int cnt;
    15     int vis;
    16     int fail;
    17 }t[maxn*60];int tot=0;
    18 int q[maxn*60]={};int head=0,tail=0;
    19 void fir(){
    20     tot=0;memset(t,0,sizeof(t));//memset(q,0,sizeof(q));
    21 }
    22 void init(int x,int j){
    23     if(j>siz-1){ t[x].cnt++; return; }
    24     int z=ch[j]-'a';
    25     if(!t[x].sig[z])t[x].sig[z]=++tot;
    26     init(t[x].sig[z],j+1);
    27 }
    28 void build_fail(){
    29     int head=0,tail=0,x,y,f;q[0]=0;
    30     while(head<=tail){
    31         x=q[head++];
    32         for(int i=0;i<26;i++)
    33             if(t[x].sig[i]){
    34                 y=t[x].sig[i];
    35                 if(x){
    36                     f=t[x].fail;
    37                     while((!t[f].sig[i])&&f)
    38                         f=t[f].fail;
    39                     t[y].fail=t[f].sig[i];
    40                 }q[++tail]=y;
    41             }
    42     }
    43 }
    44 int get_num(){//字符串中包含的单词数量,重复的不记录,
    45     //如果单词x在字符串中出现一次而在单词表中有两个则ans+2
    46     //在字符串中出现两次而单词表中有一个则ans+1
    47     int ans=0,x=0,y,z;
    48     for(int i=0;i<siz;i++){
    49         z=str[i]-'a';
    50         while((!t[x].sig[z])&&x)
    51             x=t[x].fail;
    52         x=t[x].sig[z];y=x;
    53         while(y&&(!t[y].vis)){//保证了每个结尾只访问一次
    54             ans+=t[y].cnt;
    55             t[y].vis=1;t[y].cnt=0;
    56             y=t[y].fail;
    57         }
    58     }
    59     return ans;
    60 }
    61 int main(){
    62     int T;scanf("%d",&T);
    63     while(T-->0){
    64         fir();
    65         scanf("%d",&n);
    66         for(int i=1;i<=n;i++){scanf("%s",ch);siz=strlen(ch);init(0,0);}
    67         build_fail();
    68         scanf("%s",str);siz=strlen(str);
    69         printf("%d
    ",get_num());
    70     }
    71     return 0;
    72 }
    AC自动机

     后缀数组 每次都l=<<2然后调错,我大概是个zz。一定要分清楚*2和<<1啊

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<algorithm>
     4 #include<cstring>
     5 #include<cmath>
     6 #include<queue>
     7 using namespace std;
     8 const int maxn=100010;
     9 const int pl=50;
    10 int siz;
    11 char ch[maxn+pl]={};
    12 int p[maxn+pl]={},sa[maxn+pl]={},rk[maxn+pl]={};
    13 int cnt[maxn+pl]={},temp[maxn+pl]={},height[maxn+pl]={};
    14 bool equ(int x,int y,int l){return rk[x]==rk[y]&&rk[x+l]==rk[y+l];}
    15 void SA(){
    16     for(int i=1;i<=siz;i++)sa[i]=i,rk[i]=ch[i];
    17     for(int i,sig=255,pos=0,l=0;pos<siz;sig=pos){
    18         pos=0;
    19         for(i=siz-l+1;i<=siz;i++)p[++pos]=i;
    20         for(i=1;i<=siz;i++)if(sa[i]>l)p[++pos]=sa[i]-l;
    21         for(i=1;i<=sig;i++)cnt[i]=0;
    22         for(i=1;i<=siz;i++)cnt[rk[p[i]]]++;
    23         for(i=1;i<=sig;i++)cnt[i]+=cnt[i-1];
    24         for(i=siz;i>0;i--) sa[cnt[rk[p[i]]]--]=p[i];
    25         pos=0;
    26         for(i=1;i<=siz;i++){
    27             if(equ(sa[i],sa[i-1],l))temp[sa[i]]=pos;
    28             else temp[sa[i]]=++pos;
    29         }
    30         for(i=1;i<=siz;i++)rk[i]=temp[i];
    31         if(!l)l=1;
    32         else l<<=1;
    33     }
    34     int j=0;
    35     for(int i=1;i<=siz;i++){
    36         if(rk[i]==1){j=0;continue;}
    37         if(j)j--;
    38         while(ch[i+j]==ch[sa[rk[i]-1]+j])j++;
    39         height[rk[i]]=j;
    40     }
    41 }
    42 int main(){
    43     scanf("%s",ch+1);
    44     siz=strlen(ch+1);
    45     SA();
    46     for(int i=1;i<=siz;i++)printf("%d ",sa[i]);
    47     cout<<endl;
    48     for(int i=2;i<=siz;i++)printf("%d ",height[i]);
    49     cout<<endl;
    50     return 0;
    51 }
    后缀数组

     后缀自动机,相对于它的名气好写。但是有时候还是会在犯zz错误 这里的代码copy过来了

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<algorithm>
     4 #include<cstring>
     5 #include<cmath>
     6 #include<map>
     7 using namespace std;
     8 const int maxn=100010;
     9 char ch1[maxn]={},ch2[maxn]={};
    10 int siz1,siz2;
    11 struct nod{
    12     int sig[26];
    13     int f,len;
    14 }t[maxn*2];int tot=1,la=1;
    15 void add(int z){
    16     int x=++tot;int i=la;
    17     t[x].len=t[la].len+1;
    18     for(;i&&!t[i].sig[z];i=t[i].f)
    19         t[i].sig[z]=x;
    20     if(!i)t[x].f=1;
    21     else{
    22         int p=t[i].sig[z];
    23         if(t[p].len==t[i].len+1)t[x].f=p;
    24         else{
    25             int y=++tot;
    26             t[y]=t[p];t[y].len=t[i].len+1;
    27             t[x].f=t[p].f=y;
    28             for(;i&&t[i].sig[z]==p;i=t[i].f){
    29                 t[i].sig[z]=y;
    30             }
    31         }
    32     }
    33     la=x;
    34 }
    35 int main(){
    36     memset(t,0,sizeof(t));
    37     scanf("%s",ch1+1);
    38     scanf("%s",ch2+1);
    39     siz1=strlen(ch1+1);
    40     siz2=strlen(ch2+1);
    41     for(int i=1;i<=siz1;i++)add(int(ch1[i]-'a'));
    42     int ans=0,j=1,tmp=0;
    43     for(int i=1;i<=siz2;i++){
    44         int z=ch2[i]-'a';
    45         if(t[j].sig[z]){j=t[j].sig[z];tmp++;}
    46         else{
    47             while(j&&!t[j].sig[z])
    48                 j=t[j].f;
    49             if(!j){j=1;tmp=0;}
    50             else {tmp=t[j].len+1;j=t[j].sig[z];}
    51         }
    52         if(tmp>ans)ans=tmp;
    53     }printf("%d
    ",ans);
    54     return 0;
    55 }
    SAM

  • 相关阅读:
    online ddl与pt-osc详解
    几个重点问题回顾
    死锁及常见死锁模型
    InnoDB中锁的算法(3)
    一个幻读模型引出的记录可见性判断
    jupyter notebook的使用
    l线程池抓取lianjia
    lagou数据爬取
    爬虫代理的设置
    linux如何安装和启动mongdb
  • 原文地址:https://www.cnblogs.com/137shoebills/p/8516404.html
Copyright © 2011-2022 走看看