POJ-3415 Common Substrings 后缀数组

  题目链接:http://poj.org/problem?id=3415

  求两个串的长度不小于K的公共字串的个数。

  利用height[]来维护一个单调递增的栈,即栈保存的是满足要求的heigiht数组的最小值,附加维护栈中相邻两个元素之间的个数。

  1 //STATUS:C++_AC_813MS_6532KB
  2 #include<stdio.h>
  3 #include<stdlib.h>
  4 #include<string.h>
  5 #include<math.h>
  6 #include<iostream>
  7 #include<string>
  8 #include<algorithm>
  9 #include<vector>
 10 #include<queue>
 11 #include<stack>
 12 #include<map>
 13 #include<set>
 14 using namespace std;
 15 //define
 16 #define pii pair<int,int>
 17 #define mem(a,b) memset(a,b,sizeof(a))
 18 #define lson l,mid,rt<<1
 19 #define rson mid+1,r,rt<<1|1
 20 #define PI acos(-1.0)
 21 //typedef
 22 typedef __int64 LL;
 23 typedef unsigned __int64 ULL;
 24 //const
 25 const int N=200010;
 26 const int INF=0x3f3f3f3f;
 27 const int MOD=1000007,STA=8000010;
 28 const LL LNF=1LL<<60;
 29 const double EPS=1e-8;
 30 const double OO=1e15;
 31 //Daily Use ...
 32 template<class T> inline T Min(T a,T b){return a<b?a:b;}
 33 template<class T> inline T Max(T a,T b){return a>b?a:b;}
 34 template<class T> inline T Min(T a,T b,T c){return min(min(a, b),c);}
 35 template<class T> inline T Max(T a,T b,T c){return max(max(a, b),c);}
 36 //
 37 
 38 struct Node{
 39     int l,cnt;
 40 }sta[N];
 41 
 42 char s[N/2];
 43 int num[N];
 44 int sa[N],t1[N],t2[N],c[N],rank[N],height[N];
 45 int n,m,len1,len2,K;
 46 LL ans;
 47 
 48 void build_sa(int s[],int n,int m)
 49 {
 50     int i,k,p,*x=t1,*y=t2;
 51     //第一轮基数排序
 52     for(i=0;i<m;i++)c[i]=0;
 53     for(i=0;i<n;i++)c[x[i]=s[i]]++;
 54     for(i=1;i<m;i++)c[i]+=c[i-1];
 55     for(i=n-1;i>=0;i--)sa[--c[x[i]]]=i;
 56     for(k=1;k<=n;k<<=1){
 57         p=0;
 58         //直接利用sa数组排序第二关键字
 59         for(i=n-k;i<n;i++)y[p++]=i;
 60         for(i=0;i<n;i++)if(sa[i]>=k)y[p++]=sa[i]-k;
 61         //基数排序第一关键字
 62         for(i=0;i<m;i++)c[i]=0;
 63         for(i=0;i<n;i++)c[x[y[i]]]++;
 64         for(i=1;i<m;i++)c[i]+=c[i-1];
 65         for(i=n-1;i>=0;i--)sa[--c[x[y[i]]]]=y[i];
 66         //根据sa和x数组计算新的x数组
 67         swap(x,y);
 68         p=1;x[sa[0]]=0;
 69         for(i=1;i<n;i++)
 70             x[sa[i]]=y[sa[i-1]]==y[sa[i]] && y[sa[i-1]+k]==y[sa[i]+k]?p-1:p++;
 71         if(p>=n)break;   //已经排好序,直接退出
 72         m=p;     //下次基数排序的最大值
 73     }
 74 }
 75 
 76 void getHeight(int s[],int n)
 77 {
 78     int i,j,k=0;
 79     for(i=0;i<=n;i++)rank[sa[i]]=i;
 80     for(i=0;i<n;i++){
 81         if(k)k--;
 82         j=sa[rank[i]-1];
 83         while(s[i+k]==s[j+k])k++;
 84         height[rank[i]]=k;
 85     }
 86 }
 87 
 88 void slove(int flag)
 89 {
 90     int i,j,top=-1;
 91     LL sum=0;
 92     for(i=2;i<=n;i++){
 93         if(height[i]<K){top=-1;sum=0;continue;}
 94         j=0;
 95         if((sa[i-1]<len1)==flag)j=1,sum+=(LL)height[i]-K+1;
 96         for(;top>=0 && sta[top].l>=height[i];top--){
 97             sum-=(sta[top].l-height[i])*(LL)sta[top].cnt;
 98             j+=sta[top].cnt;
 99         }
100         sta[++top].l=height[i];
101         sta[top].cnt=j;
102         if((sa[i]<len1)!=flag)
103             ans+=sum;
104     }
105 }
106 
107 int main()
108 {
109  //   freopen("in.txt","r",stdin);
110     int i,j;
111     while(~scanf("%d",&K) && K)
112     {
113         scanf("%s",s);
114         len1=strlen(s);
115         for(i=0;i<len1;i++)num[i]=s[i]-'A'+1;
116         scanf("%s",s);
117         len2=strlen(s);
118         num[i++]=80;
119         for(j=0;j<len2;i++,j++)num[i]=s[j]-'A'+1;
120         num[n=len1+len2+1]=0;
121         m=81;
122 
123         build_sa(num,n+1,m);
124         getHeight(num,n);
125         ans=0;
126         slove(1);
127         slove(0);
128 
129         printf("%I64d\n",ans);
130     }
131     return 0;
132 }

 

posted @ 2013-04-25 23:44  zhsl  阅读(330)  评论(0编辑  收藏  举报