字符串的模板 Manacher kmp ac自动机 后缀数组 后缀自动机
为何scanf("%s", str)不需要&运算 经常忘掉的字符串知识点,最好不加&,不加&最标准,指针如果像scanf里一样加&是错的,大概是未定义行为
马拉车
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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 }
kmp
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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 }
ac自动机(在poj2222提交的时候wa了好几次后来发现没有清空,而且这次重新打发现了自己之前写的漏洞。。。)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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 }
后缀数组 每次都l=<<2然后调错,我大概是个zz。一定要分清楚*2和<<1啊
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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过来了
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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 }