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 }

 

你可能感兴趣的:(substring)