POJ 3415 Common Substrings(后缀数组+单调栈)
题意: 求长度不小于k的公共子串个数
·
·
·
若不考虑时间复杂度,这题就是对两个串的每个后缀两两求LCP,取LCP不小于k的累加LCP-k+1即为答案
在这种思路的基础上,用单调栈优化即可(栈顶元素最大)
后缀数组求出height后,对height数组分组,即连续的height的值不小于k的为一组,对每组进行独立的操作
先考虑用B的后缀匹配A的后缀
按顺序遍历每组height,若遇到A的后缀,压入栈中,若遇到B的后缀,统计与前面所有出现过的A的后缀的答案,这个答案在更新栈的过程中应该一起处理,并看B能不能更新栈(B的后缀不能增加栈内元素,只能更新)
最后在用A的后缀匹配B的后缀即可
#include <cstring>
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstdlib>
using namespace std;
typedef long long ll;
const int maxn = 200010;
int n;
int sa[maxn], x[maxn], c[maxn], y[maxn], height[maxn];
char s[maxn], s1[maxn];
void SA()
{
int m = 128;
for (int i = 0; i <= m; i++)
c[i] = 0;
for (int i = 1; i <= n; i++)
c[x[i] = s[i]]++;
for (int i = 1; i <= m; i++)
c[i] += c[i - 1];
for (int i = n; i >= 1; i--)
sa[c[x[i]]--] = i;
for (int k = 1; k <= n; k <<= 1)
{
int p = 0;
for (int i = 0; i <= m; i++)
y[i] = 0;
for (int i = n - k + 1; i <= n; i++)
y[++p] = i;
for (int i = 1; i <= n; i++)
if (sa[i] > k)
y[++p] = sa[i] - k;
for (int i = 0; i <= m; i++)
c[i] = 0;
for (int i = 1; i <= n; i++)
c[x[y[i]]]++;
for (int i = 1; i <= m; i++)
c[i] += c[i - 1];
for (int i = n; i >= 1; i--)
sa[c[x[y[i]]]--] = y[i];
swap(x, y);
x[sa[1]] = 1;
p = 1;
for (int i = 2; i <= n; ++i)
x[sa[i]] = (y[sa[i]] == y[sa[i - 1]] && y[sa[i] + k] == y[sa[i - 1] + k]) ? p : ++p;
if (p >= n)
break;
m = p;
}
}
void get_height()
{
int k = 0;
for (int i = 1; i <= n; ++i)
{
if (x[i] == 1)
continue;
if (k)
--k;
int j = sa[x[i] - 1];
while (j + k <= n && i + k <= n && s[i + k] == s[j + k])
++k;
height[x[i]] = k;
}
}
ll sta[maxn], cnt[maxn];
int main()
{
int t;
while (scanf("%d", &t) && t)
{
scanf("%s%s", s + 1, s1 + 1);
int len = strlen(s + 1);
s[len + 1] = '*';
s[len + 2] = '\0';
strcat(s + 1, s1 + 1);
n = strlen(s + 1);
SA();
get_height();
ll ans = 0, sum = 0;
int tp = 0;
for (int i = 1; i <= n; i++) //B match A
{
if (sa[i] <= len)
{
ll tot = 0;
while (tp != 0 && height[sta[tp]] >= height[i + 1])
{
sum -= cnt[tp] * (height[sta[tp]] - t + 1);
sum += cnt[tp] * (height[i + 1] - t + 1);
tot += cnt[tp];
cnt[tp] = 0;
--tp;
}
sta[++tp] = i + 1;
cnt[tp] = tot + 1;
sum += height[i + 1] - t + 1;
}
else if (sa[i] > len + 1)
{
ans += sum;
if (tp != 0 && height[sta[tp]] > height[i + 1])
{
ll tot = 0;
while (tp != 0 && height[sta[tp]] > height[i + 1])
{
sum -= cnt[tp] * (height[sta[tp]] - t + 1);
sum += cnt[tp] * (height[i + 1] - t + 1);
tot += cnt[tp];
cnt[tp] = 0;
--tp;
}
sta[++tp] = i + 1;
cnt[tp] = tot ;
}
}
if(height[i+1]<t)
{
tp=0;sum=0;
}
}
tp = 0, sum = 0;
for (int i = 1; i <= n; i++) //A match B
{
if (sa[i] > len + 1)
{
ll tot = 0;
while (tp != 0 && height[sta[tp]] >= height[i + 1])
{
sum -= cnt[tp] * (height[sta[tp]] - t + 1);
sum += cnt[tp] * (height[i + 1] - t + 1);
tot += cnt[tp];
cnt[tp] = 0;
--tp;
}
sta[++tp] = i + 1;
cnt[tp] = tot + 1;
sum += height[i + 1] - t + 1;
}
else if (sa[i] <= len)
{
ans += sum;
if (tp != 0 && height[sta[tp]] > height[i + 1])
{
ll tot = 0;
while (tp != 0 && height[sta[tp]] > height[i + 1])
{
sum -= cnt[tp] * (height[sta[tp]] - t + 1);
sum += cnt[tp] * (height[i + 1] - t + 1);
tot += cnt[tp];
cnt[tp] = 0;
--tp;
}
sta[++tp] = i + 1;
cnt[tp] = tot;
}
}
if(height[i+1]<t)
{
tp=0;sum=0;
}
}
printf("%lld\n", ans);
}
return 0;
}

浙公网安备 33010602011771号