1 //Accepted 12004 KB 407 ms 2 /* 3 source:poj3693 4 time :20150819 5 by :songt 6 */ 7 /*题解: 8 搞了一天,总算弄完了 9 首先,我们来明确一个问题 1.如果一个字符串S由一个子串S1长度为L重复K次得到,那么lcp(0,l)=(K-1)*L; 10 而如果一个字符串中存在lcp(i,i+L)=m,那么字符串中就存在重复m/L+1次的子串 11 这个可以画个图看下 12 下面我们按照论文里的思路,枚举每个循环节的长度L,假设某个长度为L的子串在原字符中出现了两次以上,那么由 13 容斥原理可知,这段连续重复的子串S一定包括了s[0],s[L],s[2*L],s[3*L],...中的连续的两个,这样我们可以枚举找到 14 包括最开始的两个是哪两个,假设是s[i*L]和s[(i+1)*L],那么求lcp(i*L,(i+1)*L)=m,由1可知,原字符串中从i*L到(i+1)*L这段 15 长度为L的子串,一定重复了m/L+1,但是由于i*L和(i+1)*L不一定是重复子串的第一个开始位置,即i*L不一定对应S[0],所以我们 16 尝试调整开始的位置,假设i*L对应于S(0,L)中的某个字符,那么lcp(i*L,(i+1)*L)=m中的m就会比(m/L)*m大一点,这一点就是因为i*L 17 不对应S[0],而对应了S(0,L)中的某个字符造成的,这样我们就可以知道,多匹配的这一点长度就对应(i*L对应于S[k] 0<k<L) k到L这一段 18 长度,所以应该尝试把i*L向前移动L-m%L个字符(m%L!=0).这样我们就可以求出最大的重复次数。 19 加入最多只重复了1次也就是没有重复,那么用上面的方法也可以求得。 20 21 接下来是求最小字典序的步骤,我们在求最大重复次数的时候,保存对应可能的长度L,那么我们可以从sa[1]到sa[n]枚举, 22 如果sa[i]和某个长度L能够满足重复次数的要求,那么就得到了答案,枚举中遇到的第一个就是结果,应为sa[1]到sa[n]已经 23 按照字典序排序 24 25 */ 26 #include <cstdio> 27 #include <cstring> 28 #include <vector> 29 #include <algorithm> 30 using namespace std; 31 32 const int imax_n = 100005; 33 int wa[imax_n],wb[imax_n],wn[imax_n],wv[imax_n]; 34 int cmp(int *r,int a,int b,int l) 35 { 36 return r[a]==r[b] && r[a+l]==r[b+l]; 37 } 38 void da(int *r,int *sa,int n,int m) 39 { 40 int i,j,k,p,*x=wa,*y=wb,*t; 41 for (i=0;i<m;i++) wn[i]=0; 42 for (i=0;i<n;i++) wn[x[i]=r[i]]++; 43 for (i=1;i<m;i++) wn[i]+=wn[i-1]; 44 for (i=n-1;i>=0;i--) sa[--wn[x[i]]]=i; 45 for (j=1,p=1;p<n;j*=2,m=p) 46 { 47 for (p=0,i=n-j;i<n;i++) y[p++]=i; 48 for (i=0;i<n;i++) if (sa[i]>=j) y[p++]=sa[i]-j; 49 for (i=0;i<n;i++) wv[i]=x[y[i]]; 50 for (i=0;i<m;i++) wn[i]=0; 51 for (i=0;i<n;i++) wn[wv[i]]++; 52 for (i=1;i<m;i++) wn[i]+=wn[i-1]; 53 for (i=n-1;i>=0;i--) sa[--wn[wv[i]]]=y[i]; 54 for (t=x,x=y,y=t,p=1,x[sa[0]]=0,i=1;i<n;i++) 55 x[sa[i]]=cmp(y,sa[i-1],sa[i],j)?p-1:p++; 56 } 57 return ; 58 } 59 int rank[imax_n]; 60 int height[imax_n]; 61 int a[imax_n]; 62 char s[imax_n]; 63 int sa[imax_n]; 64 int n; 65 void calHeight(int *r,int *sa,int n) 66 { 67 int i,j,k=0; 68 for (i=1;i<=n;i++) rank[sa[i]]=i; 69 for (i=0;i<n;height[rank[i++]]=k) 70 for (k?k--:0,j=sa[rank[i]-1];r[i+k]==r[j+k];k++); 71 return ; 72 } 73 74 int min(int a,int b) 75 { 76 return a<b?a:b; 77 } 78 int dp[imax_n][20]; 79 int mm[imax_n]; 80 void initRMQ(int n,int b[]) 81 { 82 mm[0]=-1; 83 for (int i=1;i<=n;i++) 84 { 85 mm[i]=((i&(i-1))==0)?mm[i-1]+1:mm[i-1]; 86 dp[i][0]=b[i]; 87 } 88 for (int j=1;j<=mm[n];j++) 89 { 90 for (int i=1;i+(1<<j)-1<=n;i++) 91 { 92 dp[i][j]=min(dp[i][j-1],dp[i+(1<<(j-1))][j-1]); 93 } 94 } 95 } 96 int rmq(int x,int y) 97 { 98 x=rank[x]; 99 y=rank[y]; 100 if (x>y) 101 { 102 int tmp=x; 103 x=y; 104 y=tmp; 105 } 106 x++; 107 int k=mm[y-x+1]; 108 return min(dp[x][k],dp[y-(1<<k)+1][k]); 109 } 110 111 vector<int > vec; 112 113 void Deal() 114 { 115 n=strlen(s); 116 for (int i=0;i<n;i++) 117 { 118 a[i]=(int )s[i]; 119 } 120 a[n]=0; 121 da(a,sa,n+1,130); 122 calHeight(a,sa,n); 123 initRMQ(n,height); 124 vec.clear(); 125 int max_times=0; 126 for (int l=1;l<=n/2;l++) //枚举循环节的长度 127 { 128 for (int i=0;i+l<n;i+=l) //找对应子串S第一个循环节和第二个循环节的位置 129 { 130 int length=rmq(i,i+l); //求出重复的次数 131 int times=length/l+1; 132 int newpos=i-(l-length%l); 133 if (newpos>=0 && length%l && rmq(newpos,newpos+l)>length) times++; //尝试更新结果 134 if (times>max_times) 135 { 136 vec.clear(); 137 vec.push_back(l); 138 max_times=times; 139 } 140 else if (times==max_times) 141 { 142 vec.push_back(l); 143 } 144 } 145 } 146 sort(vec.begin(),vec.end()); 147 int cnt=unique(vec.begin(),vec.end())-vec.begin(); 148 //printf("max_times=%d\n",max_times); 149 //for (int i=0;i<cnt;i++) 150 //{ 151 // printf("length=%d\n",vec[i]); 152 //} 153 int start,length; 154 //printf("size=%d\n",vec.size()); 155 156 int flag=0; 157 for (int i=1;i<=n && !flag;i++) 158 { 159 for (int j=0;j<cnt && !flag;j++) 160 { 161 if (rmq(sa[i],sa[i]+vec[j])>=(max_times-1)*vec[j]) 162 { 163 start=sa[i]; 164 length=vec[j]*max_times; 165 flag=1; 166 } 167 } 168 } 169 //printf("start=%d length=%d\n",start,length); 170 for (int i=start;i<start+length;i++) 171 printf("%c",s[i]); 172 printf("\n"); 173 } 174 175 int main() 176 { 177 int T; 178 int t=0; 179 while (scanf("%s",s)!=-1) 180 { 181 if (strcmp(s,"#")==0) break; 182 printf("Case %d: ",++t); 183 Deal(); 184 } 185 return 0; 186 }
时间: 2024-10-12 21:15:26