hdu 5782 Cycle (2016多校第五場1002) 後綴數組

我們想如果匹配到第二個串的i的位置,第一個串可以匹配到哪,也就是說我們需要知道a[s]..a[.s+i-1]等於b[1]..b[i]的所有的s,可以用bitset存,然後就就枚舉i用後綴數組判斷一下就行。

#include <stdio.h>
#include <string.h>
#include <iostream>
#include <algorithm>
#include <vector>
#include <queue>
#include <set>
#include <map>
#include <string>
#include <math.h>
#include <stdlib.h>
#include <bitset>
#include <time.h>
using namespace std;
const int MAXN=20005;
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];
int RMQ[MAXN];
int mm[MAXN];
int best[15][MAXN];
int r[MAXN];
int sa[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)
{
    if(a>b)swap(a,b);
    return height[askRMQ(a+1,b)];
}
bitset<MAXN/2>a[MAXN/2],in[MAXN/2],ans,nn;
void init(){
    in[0].reset();
    in[0][0]=1;
    for(int i=1;i<MAXN/2;i++){
        in[i]=in[i-1];
        in[i].set(i);
    }
}
char x[MAXN];
char y[MAXN];
pair<int,int>p1[MAXN/2];
int main()
{
    int n;
    init();
    while(scanf("%s",x)!=EOF){
        scanf("%s",y);
        n=strlen(x);
        for(int i=0;i<n;i++){
            r[i]=x[i];
        }
        r[n]=126;
        for(int i=n+1;i<=2*n;i++){
            r[i]=y[i-n-1];
        }
        r[2*n+1]=0;
        da(r,sa,Rank,height,2*n+1,128);
        for(int i = 1;i <=2*n+1;i++)
            RMQ[i] = height[i];
        initRMQ(2*n+1);
        for(int i=0;i<n;i++){
            int w=lcp(Rank[i],Rank[n+1]);
            p1[i].first=-w;
            p1[i].second=i;
        }
        sort(p1,p1+n);
        int no=0;
        nn.reset();
        for(int i=n;i>=1;i--){
            while(no<n&&-p1[no].first>=i){
                nn.set(p1[no].second);
                no++;
            }
            a[i]=nn;
        }
        ans.reset();
        for(int i=1;i<=n;i++){
            if(i==n){
                ans|=(a[i]<<n);
                continue;
            }
            int w=lcp(Rank[n+i+1],Rank[0]);
            ans|=((a[i]<<i)&(in[i+w]^in[i-1]));
        }
        for(int i=1;i<=n;i++){
            if(ans.test(i)) printf("1");
            else printf("0");
        }
        printf("\n");
    }
    
}


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