POJ 3729 Facer’s string

来源:互联网 发布:js弹出提示框 编辑:程序博客网 时间:2024/06/04 20:20

第一次写后缀数组,真心好难,直接抄代码了,有些地方还不是很理解,先写着,留着以后再看看

/*学习后缀数组真心学习了好久,各种数组的意义往往搞不清楚后来总结出来,应该给每一个数组一个自己理解的实际意义*/ #include<stdio.h> #include<algorithm>using namespace std;const int N=100010;typedef long long ll;int wv[N],ws[N],wa[N],wb[N],rank[N],height[N],sa[N],str[N];int n,m,k,l;bool 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;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<<=1,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];swap(x,y);for(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;}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;}ll solve(int num,int len){ll ans=0;int one=0,two=0;if (sa[0]<n) one++;else two++;for(int i=1;i<=len;i++){if(height[i]<num) {if(two>0) ans+=ll(one);one=0;two=0;if(sa[i]<n) one++;else two++;}else{if(sa[i]<n) one++;else two++;}}return ans;}int main(){#ifndef ONLINE_JUDGEfreopen("in.txt","r",stdin);#endifwhile(scanf("%d%d%d",&n,&m,&k)!=EOF){l=n+m+1;for(int i=0;i<n;i++) {scanf("%d",&str[i]);str[i]++;//保证值大于1 }str[n]=10002;//用于分割两个字符串for(int i=n+1;i<l;i++) {scanf("%d",&str[i]);str[i]++;}str[l]=0;da(str,sa,l+1,10003);calheight(str,sa,l);printf("%I64d\n",solve(k,l)-solve(k+1,l));}return 0;}

--------------------------------------------------------------------分割线--------------------------------------------------------------------------------------------------------

出去吃了个饭,回来想了一下,终于弄懂了。。。。

看来一个问题很久想不出答案的时候放松放松真的很有必要。

</pre><pre name="code" class="cpp">/*
还是这个solve函数比较好理解些,根据height数组的性质,排在i,j之间的子串的最长公共子串为height[i],height[i+1]......height[j]中的最小值所以,只要包含了height[i]<k的子串,其最长公共子串长度必然小于k,由此height[i]<k的位置就形成了一个个的断点
把第一个字符串定义为A串,第二个字符串为B串考虑lcp的时候只需要考虑断点分隔出的区间里的两两组合就可以了在这里,我们把res定义为:能够生成长度>=kk的最长公共前缀的A串后缀,solve(k)-solve(k+1)就是刚好能够生成长度==k的后缀的数量,而每个后缀只能生成一个长为k的最长公共前缀。
这里还需要注意的是,如果height[i]>=k,则我们要把i-1也计算进去72 int solve(int kk, int n) 73 { 74     int res = 0; 75     for (int i = 0; i <= len; i++) 76     { 77         if (lcp[i] >= kk) 78         { 79             int one = 0, two = 0; 80             if (sa[i-1] < n) 81                 one++; 82             if (sa[i-1] > n) 83                 two++; 84             for (; i < len && lcp[i] >= kk; i++) 85             { 86                 if (sa[i] < n) 87                     one++; 88                 if (sa[i] > n) 89                     two++; 90             } 91             if (two) 92                 res += one; 93         } 94     } 95     return res; 96 }*/ 



0 0
原创粉丝点击