POJ 3261——后缀数组

题目链接:https://ac.nowcoder.com/acm/contest/924/B

后缀数组入门题,建议搞懂。

#include<cstdio>
#include<cstring>
#include<vector>
#include<set>
#include<queue>
#include<map>
#include<iostream>
#include<stack>
#include<cctype>
#include<algorithm>
using namespace std;
 
const int maxn = 20000 + 10;
int a[maxn], b[maxn];
int t1[maxn], t2[maxn], c[maxn];
int Rank[maxn], height[maxn];
int r[maxn], sa[maxn];
 
bool cmp(int *r, int a, int b, int l)
{
    return r[a] == r[b] && r[a+l] == r[b+l];
}
 
void da(int str[], int sa[], int Rank[], int height[], int n, int m)
{
    n++;
    int i, j, p, *x=t1, *y=t2;
    for(i = 0; i < m; i++) c[i] = 0;
    for(i = 0; i < n; i++) c[ x[i] = str[i] ]++;
    for(i = 1; i < m; i++) c[i] += c[i-1];
    for(i = n-1; i >= 0; i--) sa[--c[x[i]]] = i;
    for(j = 1; j <= n; j <<= 1)
    {
        p = 0;
        for(i = n-j; i < n; i++) y[p++] = i;
        for(i = 0; i < n; i++) if(sa[i] >= j) y[p++] = sa[i] - j;
        for(int i = 0; i < m; i++) c[i] = 0;
        for(int i = 0; i < n; i++) c[x[y[i]]]++;
        for(int i = 1; i < m; i++) c[i] += c[i-1];
        for(i = n-1; i >= 0; i--) sa[--c[x[y[i]]]] = y[i];
        swap(x, y);
        p = 1; x[sa[0]] = 0;
        for(i = 1; i < n; i++)
            x[sa[i]] = cmp(y, sa[i-1], sa[i], j) ? p-1 : p++;
        if(p >= n) break;
        m = p;
    }
    int k = 0;
    n--;
    for(i = 0; i <= n; i++) Rank[sa[i]] = i;
    for(i = 0; i < n; i++)
    {
        if(k) k--;
        j = sa[Rank[i]-1];
        while(str[i+k] == str[j+k]) k++;
        height[Rank[i]] = k;
    }
}
 
int RMQ[maxn], mm[maxn], best[20][maxn];
 
void initRMQ(int n)
{
    mm[0] = -1;
    for(int i = 1; i <= n; i++)
        mm[i] = ((i&(i-1))==0) ? mm[i-1]+1 : mm[i-1];
    for(int i = 1; i <= n; i++) best[0][i] = i;
    for(int i = 1; i <= mm[n]; i++)
        for(int j = 1; j+(1<<i)-1 <= n; j++)
        {
            int a = best[i-1][j];
            int b = best[i-1][j + (1<<(i-1))];
            if(RMQ[a] < RMQ[b]) best[i][j] = a;
            else best[i][j] = b;
        }
}
 
int askRMQ(int a, int b)
{
    int t;
    t = mm[b-a+1];
    b -= (1<<t)-1;
    a = best[t][a]; b = best[t][b];
    return RMQ[a] < RMQ[b] ? a : b;
}
 
int lcp(int a, int b)
{
    a = Rank[a], b = Rank[b];
    if(a > b) swap(a, b);
    return height[askRMQ(a+1, b)];
}
 
bool judge(int k, int n)
{
	int mi, mx;
	mi = mx = sa[1];
	for(int i = 2; i <= n; i++) {
		if(height[i] < k) mx = mi = sa[i];
		else {
			mx = max(mx, sa[i]);
			mi = min(mi, sa[i]);
			if(mx - mi >= k) return true;
		}
	}
	return false;
}
 
bool judge(int l, int k, int n)
{
    int cnt = 0;
    for(int i = 2;  i <= n; i++) 
    {
    	if(height[i] < l) cnt = 0;
    	else {
    		cnt++;
    		if(cnt+1 >= k) return true;
    	}
    }
    return false;
}
 
int main()
{
    int n, k;
    scanf("%d%d", &n, &k);
    for(int i = 0; i < n; i++) { scanf("%d", &a[i]); b[i] = a[i]; }
    sort(b, b+n); int len = unique(b, b+n) - b;
    for(int i = 0; i < n; i++) {
    	a[i] = upper_bound(b, b+len, a[i]) - b;
    }
    a[n] = 0;
    da(a, sa, Rank, height, n, 20005);
    int L = 0, R = n, ans = 0;
    while(L <= R)
    {
    	int mid = (L + R) >> 1;
    	if(judge(mid, k, n)) { ans = mid; L = mid + 1; }
    	else R = mid - 1;
    }
    cout << ans << endl;
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值