POJ 3729 Facer’s string
2015-03-28 18:11
253 查看
第一次写后缀数组,真心好难,直接抄代码了,有些地方还不是很理解,先写着,留着以后再看看
--------------------------------------------------------------------分割线--------------------------------------------------------------------------------------------------------
出去吃了个饭,回来想了一下,终于弄懂了。。。。
看来一个问题很久想不出答案的时候放松放松真的很有必要。
/*学习后缀数组真心学习了好久,各种数组的意义往往搞不清楚 后来总结出来,应该给每一个数组一个自己理解的实际意义*/ #include<stdio.h> #include<algorithm> using namespace std; const int N=100010; typedef long long ll; int wv ,ws ,wa ,wb ,rank ,height ,sa ,str ; 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_JUDGE freopen("in.txt","r",stdin); #endif while(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 =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 } */
相关文章推荐
- POJ 3729 Facer’s string(后缀数组)
- POJ 3729 Facer’s string(后缀数组)
- POJ 3729 Facer’s string (后缀数组 两串后缀的LCP为K的对数)
- POJ 3729 Facer’s string
- POJ 3729 Facer’s string (后缀数组)
- POJ 3729 Facer’s string 笔记
- POJ 3729 Facer's string (后缀数组)
- POJ题目3229 Facer’s string(后缀数组求a串长度为k子串有几个出现在b串)
- poj 1226 string
- Big String poj 2887
- (水)POJ-3087 模拟,map,string
- POJ 1671 Rhyme Schemes(第二类string数)
- POJ 3336 Count the string (KMP+DP,好题)
- POJ 2406 Power String 后缀数组
- POJ 3080 Blue Jeans (利用 C语言的string.h库中的strstr函数)
- POJ 1035 Spell checker(string)应用
- poj 2406 Power String (KMP)
- POJ - 3541 - Given a string…
- POJ 3827 Facer is learning to swim
- POJ 1936 All in All(string)