字符串的模板 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]='\0';
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\n",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\n",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\n",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\n",ans);
54     return 0;
55 }
SAM

 

posted @ 2018-03-06 19:54  鲸头鹳  阅读(186)  评论(0编辑  收藏  举报