POJ 3415 Common Substrings 【长度不小于 K 的公共子串的个数】
传送门:http://poj.org/problem?id=3415
题意:给定两个串,求长度不小于 k 的公共子串的个数
解题思路:
常用技巧,通过在中间添加特殊标记符连接两个串,把两个串的问题转换为 一个串的问题
按照 height 分组。
这里有两种情况
一、后缀排名中, B的后缀在后 A的后缀在前,那么 height 就是 B的后缀 与前面 A的后缀的最长相同长度
二、后缀排名中,A的后缀在前 B的后缀在后,那么 height 就是 A 的后缀与 前面 B 的后缀的最长相同长度
所以要扫两遍,分别处理这两种情况
针对第一种情况而言:
用一个单调栈维护 最小公共长度,同时要记录每个最小公共长度的状态(即当前这种最小公共长度是包含了多少个 A 前缀的了)
每一次遇到一个 B 的后缀就统计与前面的A的后缀能产生多少个长度不小于 K 的公共子串。
对于第二种情况处理的方法也是一样。
AC code:
1 /* 2 POJ 3415 3 给定两个字符串 A 和 B, 求长度不小于 K 的公共子串的个数, 4 常用技巧,通过在中间添加特殊标记符连接两个串,把两个串的问题转换为 一个串的问题 5 按照 height 分组。 6 这里有两种情况 7 一、后缀排名中, B的后缀在后 A的后缀在前,那么 height 就是 B的后缀 与前面 A的后缀的最长相同长度 8 二、后缀排名中,A的后缀在前 B的后缀在后,那么 height 就是 A 的后缀与 前面 B 的后缀的最长相同长度 9 所以要扫两遍,分别处理这两种情况 10 针对第一种情况而言: 11 用一个单调栈维护 最小公共长度,同时要记录每个最小公共长度的状态(即当前这种最小公共长度是包含了多少个 A 前缀的了) 12 每一次遇到一个 B 的后缀就统计与前面的A的后缀能产生多少个长度不小于 K 的公共子串。 13 对于第二种情况处理的方法也是一样。 14 15 */ 16 17 #include <iostream> 18 #include <algorithm> 19 #include <cmath> 20 #include <cstring> 21 #include <cstdio> 22 #define INF 0x3f3f3f3f 23 #define LL long long 24 #define rep(i, j, k) for(int i = j; i < k; i++) 25 #define inc(i, j, k) for(int i = 1; i <= k; i++) 26 using namespace std; 27 const int MAXN = 2e5+10; 28 int sa[MAXN]; 29 int t1[MAXN], t2[MAXN], c[MAXN]; 30 int Rank[MAXN], height[MAXN]; 31 32 //void Da(int s[], int n, int m) 33 //{ 34 // int i, k, p, *x = t1, *y = t2; 35 // rep(s, 0, m) c[s] = 0; 36 // rep(t, 0, n) c[x[t] = s[t]]++; 37 // rep(s, 1, m) c[s]+=c[s-1]; 38 // for(i = n-1; i >= 0; i--) sa[--c[x[i]]] = i; 39 // for(k = 1; k <= n; k <<=1){ //倍增 40 // p = 0; 41 // for(i = n-k; i < n; i++) y[p++] = i; 42 // for(i = 0; i < n; i++) if(sa[i] >= k) y[p++] = sa[i]-k; 43 // for(i = 0; i < m; i++) c[i] = 0; 44 // for(i = 0; i< n; i++) c[x[y[i]]]++; 45 // for(i = 1; i < m; i++) c[i]+=c[i-1]; 46 // for(i = n-1; i >= 0; i--) sa[--c[x[y[i]]]] = y[i]; 47 // swap(x, y); 48 // p = 1; x[sa[0]] = 0; 49 // for(i = 1; i < n; i++) 50 // x[sa[i]] = y[sa[i-1]]==y[sa[i]]&&y[sa[i-1]+k]==y[sa[i+k]]?p-1:p++; 51 // if(p >= n) break; 52 // m = p; 53 // } 54 //} 55 // 56 //void getHeight(int s[], int n) 57 //{ 58 // int i, j, k = 0; 59 // for(i = 0; i <= n; i++) Rank[sa[i]] = i; 60 // for(i = 0; i < n; i++){ 61 // if(k) k--; 62 // j = sa[Rank[i]-1]; 63 // while(s[i+k] == s[j+k])k++; 64 // height[Rank[i]] = k; 65 // } 66 //} 67 68 void Da(int s[],int n,int m) 69 { 70 int i,k,p,*x=t1,*y=t2; 71 for(i=0;i<m;i++)c[i]=0; 72 for(i=0;i<n;i++)c[x[i]=s[i]]++; 73 for(i=1;i<m;i++)c[i]+=c[i-1]; 74 for(i=n-1;i>=0;i--)sa[--c[x[i]]]=i; 75 for(k=1;k<=n;k<<=1) 76 { 77 p=0; 78 for(i=n-k;i<n;i++)y[p++]=i; 79 for(i=0;i<n;i++)if(sa[i]>=k)y[p++]=sa[i]-k; 80 for(i=0;i<m;i++)c[i]=0; 81 for(i=0;i<n;i++)c[x[y[i]]]++; 82 for(i=1;i<m;i++)c[i]+=c[i-1]; 83 for(i=n-1;i>=0;i--)sa[--c[x[y[i]]]]=y[i]; 84 swap(x,y); 85 p=1;x[sa[0]]=0; 86 for(i=1;i<n;i++) 87 x[sa[i]]=y[sa[i-1]]==y[sa[i]]&&y[sa[i-1]+k]==y[sa[i]+k]?p-1:p++; 88 if(p>=n)break; 89 m=p; 90 } 91 } 92 93 void getHeight(int s[],int n) 94 { 95 int i,j,k=0; 96 for(i=0;i<=n;i++)Rank[sa[i]]=i; 97 for(i=0;i<n;i++) 98 { 99 if(k)k--; 100 j=sa[Rank[i]-1]; 101 while(s[i+k]==s[j+k])k++; 102 height[Rank[i]]=k; 103 } 104 } 105 106 char str1[MAXN], str2[MAXN]; 107 int r[MAXN]; 108 int sta[MAXN], stb[MAXN]; 109 110 int main() 111 { 112 int k; 113 int n; 114 int len1, len2; 115 while(~scanf("%d", &k) && k){ 116 scanf("%s %s", &str1, &str2); 117 len1 = strlen(str1); 118 len2 = strlen(str2); 119 // cout << str1 << endl << str2 << endl; 120 n = len1+len2+1; 121 for(int i = 0; i < len1; i++) r[i]=str1[i]; 122 r[len1] = 1; 123 for(int i = 0; i < len2; i++) r[i+len1+1]=str2[i]; 124 r[len1+len2+1] = 0; 125 Da(r, n+1, 128); 126 getHeight(r, n); 127 // for(int i = 0; i <= n; i++) cout << r[i] << " " ; 128 // puts(""); 129 LL ans = 0, ss = 0; 130 int top = 0; 131 for(int i = 2; i <= n; i++){ 132 if(height[i] < k){ 133 top = 0; 134 ss = 0; 135 continue; 136 } 137 int cnt = 0; 138 if(sa[i-1] < len1){ 139 cnt++; 140 ss+=height[i]-k+1; 141 } 142 while(top > 0 && height[i] <= sta[top-1]){ 143 top--; 144 ss-=stb[top]*(sta[top]-height[i]); 145 cnt+=stb[top]; 146 } 147 sta[top] = height[i]; 148 stb[top++] = cnt; 149 if(sa[i] > len1) ans+=ss; 150 } 151 // cout << ans << endl; 152 ss = 0;top = 0; 153 for(int i = 2; i <= n; i++){ 154 if(height[i] < k){ 155 top = 0; 156 ss = 0; 157 continue; 158 } 159 int cnt = 0; 160 if(sa[i-1] > len1){ 161 cnt++; 162 ss+=height[i]-k+1; 163 } 164 while(top > 0 && height[i] <= sta[top-1]){ 165 top--; 166 ss-=stb[top]*(sta[top]-height[i]); 167 cnt+=stb[top]; 168 } 169 sta[top] = height[i]; 170 stb[top++] = cnt; 171 // cout << ss << endl; 172 if(sa[i] < len1) ans+=ss; 173 } 174 printf("%lld\n", ans); 175 } 176 return 0; 177 }