您的位置:首页 > 其它

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 }
*/
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: