【POJ 3415】Common Substrings(后缀数组+单调栈)

Description

A substring of a string T is defined as:

 

T(ik)=TiTi+1...Ti+k-1, 1≤ii+k-1≤|T|.

 

Given two strings AB and one integer K, we define S, a set of triples (ijk):

 

S = {(ijk) | kKA(ik)=B(jk)}.

 

You are to give the value of |S| for specific AB and K.

Input

The input file contains several blocks of data. For each block, the first line contains one integer K, followed by two lines containing strings A and B, respectively. The input file is ended by K=0.

1 ≤ |A|, |B| ≤ 105
1 ≤ K ≤ min{|A|, |B|}
Characters of A and B are all Latin letters.

 

Output

For each case, output an integer |S|.

Sample Input

2
aababaa
abaabaa
1
xx
xx
0

Sample Output

22
5

【题目大意】

 给定两个串,问大于长度 k 的子串一共有多少对

 

【解题思路】

首先相同子串就想到了后缀数组,先两个串连起来一波操作得到 height 和 SA

然后考虑如何得到这个结果

许多代码使用了后缀数组加单调栈,但是我并不明白究竟是什么原因导致他们选用这种方法

首先考虑,如何区分不同的子串,height 从1到 n 的情况中,去掉第一个字符,然后剩下的又是什么

首先先比较 height ,height大于等于 k 说明有解

再判断另外一个是否是在另一个字符串中

而这个积累的过程,就利用单调栈进行储存,将现在的 height 的值,储存下来,在之后遇到合适的值传入的过程中,就会把这个值积累上去

有点疑问的地方在于这个清空操作,height 一步一步的往后推,怎么样才能实现

因为 height 和前面的相同,所以能够确定是一样的子串

 

 

 【代码】

 

  1 #include<cstdio>
2
#include<cstring> 3 #include<string> 4 #include<iostream> 5 #define ll long long 6 using namespace std; 7 const int MAXN = 200000 + 10; 8 int n = 0; 9 int k,lena,lenb; 10 ll sta[MAXN][2]; 11 char a[MAXN], b[MAXN]; 12 int SA[MAXN], height[MAXN],rak[MAXN]; 13 int x[MAXN], y[MAXN], c[MAXN]; 14 void init() 15 { 16 for (int i = 0; i <= 128; i++) 17 x[i] = 0, y[i] = 0, c[i] = 0; 18 for(int i=0;i<=n;i++) 19 SA[i] = 0, rak[i] = 0, height[i] = 0; 20 memset(a, 0, sizeof(a)); 21 memset(b, 0, sizeof(b)); 22 n = 0; 23 } 24 void get_SA(char *s) 25 { 28 int m = 128; 29 for (int i = 1; i <= n; i++) 30 ++c[x[i] = s[i]]; 31 32 for (int i = 2; i <= m; i++) 33 c[i] += c[i - 1]; 34 35 for (int i = n; i >= 1; i--) 36 SA[c[x[i]]--] = i; 37 38 for (int k = 1; k <= n; k <<= 1) 39 { 40 int num = 0; 41 for (int i = n - k + 1; i <= n; i++) y[++num] = i; 43 for (int i = 1; i <= n; i++) 45 if (SA[i] > k) 47 y[++num] = SA[i] - k; 49 for (int i = 1; i <= m; i++) 50 c[i] = 0; 51 for (int i = 1; i <= n; i++) 52 c[x[i]]++; 54 for (int i = 2; i <= m; i++) 55 c[i] += c[i - 1]; 57 for (int i = n; i >= 1; i--) 58 SA[c[x[y[i]]]--] = y[i], y[i] = 0; 59 swap(x, y); 60 x[SA[1]] = 1; num = 1; 61 for (int i = 2; i <= n; i++) 62 x[SA[i]] = (y[SA[i]] == y[SA[i - 1]] && y[SA[i] + k] == y[SA[i - 1] + k]) ? num : ++num; 63 if (num == n) break; 64 m = num; 65 } 66 for (int i = 1; i <= n; i++) 67 rak[SA[i]] = i; 68 } 69 void get_height(char *s) 70 { 71 int k = 0; 72 for (int i = 1; i <= n; i++) 73 { 74 if (k) k--; 75 int j = SA[rak[i] - 1]; 76 while (i + k <= n && j + k <= n && s[i + k] == s[j + k]) k++; 77 height[rak[i]] = k; 78 } 79 } 80 ll solve() 81 { 82 ll ans = 0; 83 ll top = 0; 84 ll tot = 0; 85 for (int i = 1; i <= n; i++) 86 { 87 if (height[i]<k) 88 { 89 top = 0, tot = 0; 90 } 91 else 92 { 93 int cnt = 0; 94 if (SA[i - 1] <= lena) 95 { 96 cnt++, tot += height[i] + 1 - k ; 97 //判断是否符合题意 98 //cnt++当前有一个符合条件 99 //tot 计算符合条件的结果 100 } 101 while (top && height[i] <= sta[top - 1][0]) 102 { 103 top--; 104 tot += (height[i] - sta[top][0]) * sta[top][1]; 105 //有一个符合条件的 106 cnt += sta[top][1]; 107 108 } 109 //寻找之前符合条件的 110 sta[top][0] = height[i], sta[top][1] = cnt; top++; 111 //将当前的放入栈中 112 if (SA[i] > lena+1) ans += tot; 113 } 114 } 115 top = tot = 0; 116 for (int i = 1; i <= n; i++) 117 { 118 if (height[i] < k) 119 { 120 top = 0, tot = 0; 121 } 122 else 123 { 124 int cnt = 0; 125 if (SA[i - 1] > lena+1) 126 { 127 cnt++, tot += height[i] + 1 - k; 128 //判断是否符合题意 129 //cnt++当前有一个符合条件 130 //tot 计算符合条件的结果 131 } 132 while (top && height[i] <= sta[top - 1][0]) 133 { 134 top--; 135 tot += (height[i] - sta[top][0]) * sta[top][1]; 136 //有一个符合条件的 137 cnt += sta[top][1]; 138 139 } 140 //寻找之前符合条件的 141 sta[top][0] = height[i], sta[top][1] = cnt; top++; 142 //将当前的放入栈中 143 if (SA[i] <= lena) ans += tot; 144 } 145 } 146 return ans; 147 } 148 int main() 149 { 150 while (scanf("%d", &k) && k) 151 { 152 init(); 153 getchar(); 154 scanf("%s%s", a+1, b+1); 155 int len = strlen(b+1); 156 n = strlen(a + 1); 157 lena = n; 158 a[++n] ='#'; 159 lenb = n; 160 for (int i = 1; i <= len; i++) 161 a[++n] = b[i]; 162 get_SA(a); 163 get_height(a); 164 printf("%lld\n", solve()); 165 } 166 return 0; 167 }

 

posted @ 2019-09-27 19:35  rentu  阅读(153)  评论(0编辑  收藏  举报