题意:求n个串的最长公共子串,子串出现在一个串中可以是它的反转串出现。总长<=10^4.
题解:
对于每个串,把反转串也连进去。
二分长度,分组,判断每个组。
1 #include2 #include 3 #include 4 #include 5 using namespace std; 6 7 const int N=2*21000; 8 int n,sl,cl,c[N],rk[N],sa[N],Rs[N],wr[N],y[N],h[N],st[N],ed[N],fst[N],fed[N]; 9 char s[N]; 10 bool vis[N]; 11 12 void get_sa(int m) 13 { 14 for(int i=1;i<=cl;i++) rk[i]=c[i]; 15 for(int i=1;i<=m;i++) Rs[i]=0; 16 for(int i=1;i<=cl;i++) Rs[rk[i]]++; 17 for(int i=1;i<=m;i++) Rs[i]+=Rs[i-1]; 18 for(int i=cl;i>=1;i--) sa[Rs[rk[i]]--]=i; 19 20 int ln=1,p=0; 21 while(p ln) y[++k]=sa[i]-ln; 26 27 for(int i=1;i<=cl;i++) wr[i]=rk[y[i]]; 28 for(int i=1;i<=m;i++) Rs[i]=0; 29 for(int i=1;i<=cl;i++) Rs[wr[i]]++; 30 for(int i=1;i<=m;i++) Rs[i]+=Rs[i-1]; 31 for(int i=cl;i>=1;i--) sa[Rs[wr[i]]--]=y[i]; 32 33 for(int i=1;i<=cl;i++) wr[i]=rk[i]; 34 for(int i=cl+1;i<=cl+ln;i++) wr[i]=0; 35 p=1;rk[sa[1]]=1; 36 for(int i=2;i<=cl;i++) 37 { 38 if(wr[sa[i]]!=wr[sa[i-1]] || wr[sa[i]+ln]!=wr[sa[i-1]+ln]) p++; 39 rk[sa[i]]=p; 40 } 41 ln*=2,m=p; 42 } 43 sa[0]=0,rk[0]=0; 44 } 45 46 void get_h() 47 { 48 int k=0,j; 49 for(int i=1;i<=cl;i++) if(rk[i]!=1) 50 { 51 j=sa[rk[i]-1]; 52 if(k) k--; 53 while(c[i+k]==c[j+k] && i+k<=cl && j+k<=cl) k++; 54 h[rk[i]]=k; 55 } 56 h[0]=0; 57 } 58 59 int idx(int x) 60 { 61 for(int i=1;i<=n;i++) 62 if((st[i]<=x && x<=ed[i]) || (fst[i]<=x && x<=fed[i])) return i; 63 } 64 65 bool check(int k) 66 { 67 memset(vis,0,sizeof(vis)); 68 for(int i=1;i<=cl;i++) 69 { 70 if(h[i] 1) c[++cl]=++num;100 st[i]=cl+1;for(int j=1;j<=sl;j++) c[++cl]=s[j];ed[i]=cl;101 c[++cl]=++num;102 fst[i]=cl+1;for(int j=sl;j>=1;j--) c[++cl]=s[j];fed[i]=cl;103 }104 if(n==1) {printf("%d\n",sl);continue;}105 get_sa(300);106 get_h();107 // for(int i=1;i<=cl;i++) printf("%c",c[i]);printf("\n");108 // for(int i=1;i<=cl;i++) printf("%d ",c[i]);printf("\n");109 // for(int i=1;i<=cl;i++) printf("%d ",sa[i]);printf("\n");110 // for(int i=1;i<=cl;i++) printf("%d ",rk[i]);printf("\n");111 // for(int i=1;i<=cl;i++) printf("%d ",h[i]);printf("\n");112 int l=0,r=cl,mid;113 while(l
这一题我曾经用kmp暴力水过。。贴一下代码
1 #include2 #include 3 #include 4 #include 5 #include 6 #include 7 using namespace std; 8 9 const int N=110,Inf=(int)1e9;10 char s[N][N],c1[N],c2[N];11 int n,id,cl,l[N],nt[N],nxt[N];12 13 void kmp_nt()14 {15 nt[1]=0;16 for(int i=2,p=0;i<=cl;i++)17 {18 while(c1[p+1]!=c1[i] && p) p=nt[p];19 if(c1[p+1]==c1[i]) p++;20 nt[i]=p;21 }22 23 nxt[1]=0;24 for(int i=2,p=0;i<=cl;i++)25 {26 while(c2[p+1]!=c2[i] && p) p=nxt[p];27 if(c2[p+1]==c2[i]) p++;28 nxt[i]=p;29 }30 }31 32 bool kmp_td(int x)33 {34 for(int i=1,p=0;i<=l[x];i++)35 {36 while(c1[p+1]!=s[x][i] && p) p=nt[p];37 if(c1[p+1]==s[x][i]) p++;38 if(p==cl) return 1;39 }40 for(int i=1,p=0;i<=l[x];i++)41 {42 while(c2[p+1]!=s[x][i] && p) p=nxt[p];43 if(c2[p+1]==s[x][i]) p++;44 // td[i]=p;45 if(p==cl) return 1;46 }47 return 0;48 }49 50 bool check(int len)51 {52 for(int i=1;i+len-1<=l[id];i++)53 {54 cl=0;55 for(int j=i;j<=i+len-1;j++) 56 c1[++cl]=s[id][j],c2[len-cl+1]=s[id][j];57 kmp_nt();58 bool bk=1;59 for(int j=1;j<=n;j++)60 if(!kmp_td(j)) {bk=0;break;}61 if(bk) return 1;62 }63 }64 65 int main()66 {67 freopen("a.in","r",stdin);68 freopen("vio.out","w",stdout);69 int T;70 scanf("%d",&T);71 while(T--)72 {73 scanf("%d",&n);74 int ll=0,rr=Inf,mid;75 for(int i=1;i<=n;i++)76 {77 scanf("%s",s[i]+1);78 l[i]=strlen(s[i]+1);79 if(l[i]