poj3294 后缀数组
后缀数组多个字符串问题。
先求出height[]数组,然后二分求最大的长度。
但是条件需要改变。如果出现次数大于一般那就满足。然后就要解决如何判断那一段属于其中一个字符串。
所以先处理出长度。并且不断标记,如果在长度其中,将那个长度标记。那就不会出现自己与自己的相同情况了。
RE了很多次,字符串输入的时候同时存入整数,防止过大可能使字符串出现问题。
#include<iostream> #include<stdio.h> #include<string.h> #include<stdlib.h> #include<string> #include<map> #define LL long long using namespace std; #define maxn 1110000 int max(int x,int y) {return x>y?x:y;} int min(int x,int y) {return x<y?x:y;} int wa[maxn],wb[maxn],wv[maxn],WS[maxn]; int vex[maxn],size,vis[120],pre[maxn],cou;//vex存每一段的长度 size表示个数 pre存满足条件的开始位置 cou存满足的个数 int cmp(int *r,int a,int b,int l) {return r[a]==r[b]&&r[a+l]==r[b+l];} void da(int *r,int *sa,int n,int m) { int i,j,p,*x=wa,*y=wb,*t; for(i=0;i<m;i++) WS[i]=0; for(i=0;i<n;i++) WS[x[i]=r[i]]++; for(i=1;i<m;i++) WS[i]+=WS[i-1]; for(i=n-1;i>=0;i--) sa[--WS[x[i]]]=i; for(j=1,p=1;p<n;j*=2,m=p) { for(p=0,i=n-j;i<n;i++) y[p++]=i; for(i=0;i<n;i++) if(sa[i]>=j) y[p++]=sa[i]-j; for(i=0;i<n;i++) wv[i]=x[y[i]]; for(i=0;i<m;i++) WS[i]=0; for(i=0;i<n;i++) WS[wv[i]]++; for(i=1;i<m;i++) WS[i]+=WS[i-1]; for(i=n-1;i>=0;i--) sa[--WS[wv[i]]]=y[i]; for(t=x,x=y,y=t,p=1,x[sa[0]]=0,i=1;i<n;i++) x[sa[i]]=cmp(y,sa[i-1],sa[i],j)?p-1:p++; } return; } int Rank[maxn],height[maxn]; void calheight(int *r,int *sa,int n) { int i,j,k=0; for(i=1;i<=n;i++) Rank[sa[i]]=i; for(i=0;i<n;height[Rank[i++]]=k) for(k?k--:0,j=sa[Rank[i]-1];r[i+k]==r[j+k];k++); return; } int r[maxn],sa[maxn]; int ok(int x,int n,int k) { cou=0; int i,j,ret=0; memset(vis,0,sizeof(vis)); for(i=1;i<=n;i++) { if(height[i]>=x) { for(j=1;j<size;j++) { if(sa[i]>vex[j-1]&&sa[i]<vex[j])//由于自己添加的并不会相同 所以只要满足在中间位置就可以 { if(!vis[j])//如果满足就标记掉那个位置 { vis[j]=1; ret++; } } if(sa[i-1]>vex[j-1]&&sa[i-1]<vex[j]) { if(!vis[j]) { vis[j]=1; ret++; } } } } else { if(ret>k) { pre[cou++]=sa[i-1]; } ret=0; memset(vis,0,sizeof(vis)); } } if(ret>k) { pre[cou++]=sa[n]; } if(cou>0)//表面有满足条件的 return 1; return 0; } char s[maxn],c[maxn]; int main() { int i,n,ff=0,fl; while(cin>>n) { if(!n)break; size=1; int len=0; int num=123; for(i=0;i<n;i++) { scanf("%s",c); int fl=strlen(c); for(int p=0;p<fl;p++) { r[len]=c[p];//修改了此处 过了 之前是先存在s[]中 但是会出现问题 因为100多可能字符有问题 s[len++]=c[p]; } vex[size++]=len; r[len]=num; s[len++]=num++; } len--; int j=len; r[j]=0; da(r,sa,j+1,250); calheight(r,sa,j); int left,right,mid,ans=-1; left=1,right=j,cou=0; while(left<=right) { mid=(left+right)/2; if(ok(mid,j,n/2)) { fl=cou; ans=mid; left=mid+1; } else right=mid-1; } /*for(i=1;i<=j;i++) printf("%d ",height[i]); printf("\n");*/ if(ff) printf("\n"); else ff=1; if(ans<=1) { printf("?\n"); continue; } //printf("%d\n",ans); for(i=0;i<fl;i++) { for(j=0;j<ans;j++) { printf("%c",s[pre[i]+j]); } printf("\n"); } } } /* 5 abcdef bcdea hzbcde bcdyz acxq */