码迷,mamicode.com
首页 > 其他好文 > 详细

poj3693

时间:2015-08-20 01:10:54      阅读:123      评论:0      收藏:0      [点我收藏+]

标签:

  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 }

 

poj3693

标签:

原文地址:http://www.cnblogs.com/djingjing/p/4743759.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!