POJ 3261 (后缀数组 二分) Milk Patterns

这道题和UVa 12206一样,求至少重复出现k次的最长字串。

首先还是二分最长字串的长度len,然后以len为边界对height数组分段,如果有一段包含超过k个后缀则符合要求。

 #include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std; const int maxn = + ;
const int maxm = + ; int s[maxn];
int sa[maxn], height[maxn], rank[maxn];
int t[maxn], t2[maxn], c[maxm];
int n, k; void build_sa(int m)
{
int i, *x = t, *y = t2;
for(i = ; i < m; i++) c[i] = ;
for(i = ; i < n; i++) c[x[i] = s[i]]++;
for(i = ; i < m; i++) c[i] += c[i - ];
for(i = n - ; i >= ; i--) sa[--c[x[i]]] = i;
for(int k = ; k <= n; k <<= )
{
int p = ;
for(i = n - k; i < n; i++) y[p++] = i;
for(i = ; i < n; i++) if(sa[i] >= k) y[p++] = sa[i] - k;
for(i = ; i < m; i++) c[i] = ;
for(i = ; i < n; i++) c[x[y[i]]]++;
for(i = ; i < m; i++) c[i] += c[i - ];
for(i = n - ; i >= ; i--) sa[--c[x[y[i]]]] = y[i];
swap(x, y);
p = ; x[sa[]] = ;
for(i = ; i < n; i++)
x[sa[i]] = y[sa[i]]==y[sa[i-]] && y[sa[i]+k]==y[sa[i-]+k] ? p - : p++;
if(p >= n) break;
m = p;
}
} void build_height()
{
int i, j, k = ;
for(i = ; i < n; i++) rank[sa[i]] = i;
for(i = ; i < n; i++)
{
if(k) k--;
j = sa[rank[i] - ];
while(s[i + k] == s[j + k]) k++;
height[rank[i]] = k;
}
} bool ok(int len)
{
int cnt = ;
for(int i = ; i < n; i++)
{
if(i == || height[i] < len) cnt = ;
if(++cnt >= k) return true;
}
return false;
} int main()
{
//freopen("in.txt", "r", stdin); scanf("%d%d", &n, &k);
for(int i = ; i < n; i++)
{
scanf("%d", &s[i]);
s[i]++;
}
s[n] = ;
build_sa();
build_height(); int L = , R = n;
while(L < R)
{
int M = (L + R + ) / ;
if(ok(M)) L = M;
else R = M - ;
} printf("%d\n", L); return ;
}

代码君

上一篇:Oracle 给表添加主键和使ID自增、触发器、创建结构一样的表


下一篇:GA代码中的细节