初涉后缀数组

以POJ 1743为例。模板中的基数排序基于前向星。

具体证明过程详见 算法合集之《后缀数组——处理字符串的有力工具》,很不错的一篇论文。

#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <queue>
#include <cmath>
#include <stack>
#include <map>
#include <ctime>
#include <iomanip>

#pragma comment(linker, "/STACK:1024000000");
#define EPS (1e-6)
#define LL long long
#define ULL unsigned long long
#define _LL __int64
#define INF 0x3f3f3f3f
#define Mod 1000000007

using namespace std;

const int MAXN = 20510;

int s[MAXN];

int Rank[2*MAXN],sa[2*MAXN],tr[2*MAXN],high[MAXN];

struct N
{
    int v,next;
}edge[2*MAXN];

int tail[MAXN],Top;

inline void Link(int u,int v)
{
    edge[Top].v = v;
    edge[Top].next = -1;
    edge[tail[u]].next = Top;
    tail[u] = Top++;
}

void Get_SA(int *s,int n)
{
    memset(Rank,0,sizeof(Rank));
    memset(sa,0,sizeof(sa));

    int i,j,k,ans,site;

    for(i = max(n,200);i >= 0; --i)
        tail[i] = i,edge[i].next = -1;

    Top = max(n,200)+1;

    for(i = 1; i <= n; ++i)
        Link(s[i],i);

    ans = 1,site = 1;

    for(i = 0; i <= 200; ++i)
    {
        for(j = edge[i].next; j != -1; j = edge[j].next)
            sa[site++] = edge[j].v,Rank[edge[j].v] = ans;
        if(edge[i].next != -1)
            ans++;
        tail[i] = i,edge[i].next = -1;
    }

    for(k = 1;k <= n; k <<= 1)
    {
        Top = n+1;
        for(i = 1;i <= n; ++i)
            Link(Rank[sa[i]+k],sa[i]);

        site = 1;

        for(i = 0;i <= n; ++i)
        {
            for(j = edge[i].next;j != -1; j = edge[j].next)
                sa[site++] = edge[j].v;
            tail[i] = i,edge[i].next = -1;
        }

        Top = n+1;

        for(i = 1;i <= n; ++i)
            Link(Rank[sa[i]],sa[i]);

        site = 1;

        for(i = 1;i <= n; ++i)
        {
            for(j = edge[i].next;j != -1; j = edge[j].next)
                sa[site++] = edge[j].v;
            tail[i] = i,edge[i].next = -1;
        }

        for(tr[sa[1]] = 1,i = 2,ans = 1;i <= n; ++i)
        {
            if(Rank[sa[i]] != Rank[sa[i-1]] || Rank[sa[i]+k] != Rank[sa[i-1]+k])
                ans++;
            tr[sa[i]] = ans;
        }

        for(i = 1;i <= n; ++i)
            Rank[i] = tr[i];
        if(ans >= n)
            break;
    }

    for(i = 1,k = 1;i <= n; ++i)
    {
        if(k) k--;
        if(Rank[i] == 1) {k = 0;high[1] = n-sa[1]+1;continue;}
        j = sa[Rank[i]-1];
        while(i+k <= n && j+k <= n && s[i+k] == s[j+k])
            k++;
        high[Rank[i]] = k;
    }
//
//    for(i = 1;i <= n; ++i)
//        printf("i = %2d SA = %2d Rank = %2d high = %2d\n",i,sa[i],Rank[i],high[i]);

    //以上为Rank,SA,HIGH的构造过程
}

bool Check(int mid,int n)
{
    int L = sa[1],R = sa[1],i;

    for(i = 2;i <= n; ++i)
    {
        if(high[i] >= mid)
        {
            L = min(sa[i],L),R = max(sa[i],R);
            if(L+mid < R)
                return true;
        }
        else
        L = sa[i],R = sa[i];
    }
    return false;
}

int main()
{
    int i,n;

    while(scanf("%d",&n) && n)
    {
        for(i = 1;i <= n; ++i)
            scanf("%d",&s[i]);

        for(i = n;i >= 2; --i)
            s[i] -= s[i-1]-100;

        Get_SA(s,n);

        int mid,anw = 0,Low = 1,High = n;

        while(Low <= High)
        {
            mid = (Low + High)>>1;

            if(Check(mid,n))
                anw = max(anw,mid),Low = mid+1;
            else
                High = mid-1;
        }

        printf("%d\n",anw+1 < 5 ? 0 : anw+1);
    }
    return 0;
}






评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值