【後綴數組】 POJ 3882 Stammering Aliens 可重疊出現k次字符串

點擊打開鏈接

題意:m表示至少出現m次的字符串,要求最長,並輸出最後一次的子串的位置

height [ i ] 表示 sa [ i ] 與 sa [ i -1 ] 的公共長度

二分最長串的長度

如果找到連續的k-1個 height 大於等於 長度len 即存在長度爲len的串

這時候記錄下最靠右邊的串的位置

(需要特判 m==1 的時候

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include <string>
#include <iostream>
#include <algorithm>
using namespace std;
#include <queue>
#include <stack>
#include <vector>
#include <list>
#include <deque>
#include <set>
#pragma comment(linker, "/STACK:1024000000,1024000000")
#include <map>
typedef long long LL;
const int INF = 1<<29;
const int mod = 2552 ;
const int MAXN = 50010;
int t1[MAXN],t2[MAXN],c[MAXN]; //求SA數組需要的中間變量,不需要賦值
//待排序的字符串放在s數組中,從s[0] 到s[n-1], 長度爲n, 且最大值小於m,
//除s[n-1] 外的所有s[i] 都大於0, r[n-1]=0
//函數結束以後結果放在sa數組中
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;
//第一輪基數排序,如果s的最大值很大,可改爲快速排序
    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;
//直接利用sa數組排序第二關鍵字
        for(i = n-j; i < n; i++)y[p++] = i; //後面的j 個數第二關鍵字爲空的最小
        for(i = 0; i < n; i++) if(sa[i] >= j)y[p++] = sa[i] - j;
//這樣數組y保存的就是按照第二關鍵字排序的結果
//基數排序第一關鍵字
        for(i = 0; i < m; i++)c[i] = 0;
        for(i = 0; i < n; i++)c[x[y[i]]]++;
        for(i = 1; i < m; i++)c[i] += c[i-1];
        for(i = n-1; i >= 0; i --)sa[--c[x[y[i]]]] = y[i];
//根據sa和x數組計算新的x數組
        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 rank[MAXN],height[MAXN];
char str[MAXN];
int r[MAXN];
int sa[MAXN];
int wei;
int gao(int ll,int n,int k)
{
    int ans=0;
    int now=0;
    wei=0;
    for(int i=2;i<=n;i++)
    {
        if(height[i]>=ll)
            now++;
        else
        {
            ans=max(ans,now);
            if(now+1>=k)
            {
                for(int j=i-1;now+1;j--,now--)
                    wei=max(sa[j],wei);
            }
            now=0;
        }
    }
    ans=max(ans,now);
    if(now+1>=k)
    {
        for(int j=n;now+1;j--,now--)
            wei=max(sa[j],wei);
    }
    if(ans+1>=k)
    {
        return 1;
    }
    else return 0;
}
int main()
{
    int k;
    while(scanf("%d",&k),k)
    {
        scanf("%s",str);
        int len = strlen(str);
        if(k==1)
        {
            printf("%d %d\n",len,0);
            continue;
        }
        int n=len;
        for(int i = 0; i < len; i++)
            r[i] = str[i];
        da(r,sa,rank,height,n,128);
        int ll=1,rr=len,ans=0,out=0;
        while(ll<=rr)
        {
            int mm=(ll+rr)>>1;
            if(gao(mm,n,k))
            {
                if(ans<mm)
                    ans=mm,out=wei;
                ll=mm+1;
            }
            else rr=mm-1;
        }
        if(ans==0)
            printf("none\n");
        else
            printf("%d %d\n",ans,out);
    }
    return 0;
}
/*
*/


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章