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 }