首页 > 代码库 > POJ-2774 后缀数组基础题

POJ-2774 后缀数组基础题

POJ 2774

题意:求两个字符串的最长公共子序列。

总结:搞了半天还是不太理解,看着大神博客强行敲的。。而且还看到有hash+二分做的。

// POJ-2774
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cstring>
#include<string>
#include<cmath>
#include<queue>
#include<stack>
#include<map>
#include<bitset>
#include<vector>
#include<set>
using namespace std;
#pragma comment(linker, "/STACK:102400000,102400000")
#define F(i,a,b)  for (int i=a;i<b;i++)
#define FF(i,a,b) for (int i=a;i<=b;i++)
#define mes(a,b)  memset(a,b,sizeof(a))
#define INF 0x3f3f3f3f
typedef long long ll;
const int N = 3e5+10;

char str[N], str1[N];

//这些应该可以做模板了。。
int wa[N], wb[N], wsf[N], wv[N], sa[N];
int rankn[N], height[N], s[N];
int cmp(int *r, int a, int b, int k)
{
    return r[a]==r[b] && r[a+k]==r[b+k];
}
void Getsa(int *r, int *sa, int n, int m)
{
    int i, j, p, *x=wa, *y=wb, *t;
    F(i,0,m) wsf[i]=0;
    F(i,0,n) wsf[x[i]=r[i]]++;
    F(i,1,m) wsf[i]+= wsf[i-1];
    for(i=n-1; i>=0; i--) sa[--wsf[x[i]]]=i;
    p=1, j=1;
    for( ; p<n; j*=2, m=p) {
        for(p=0, i=n-j; i<n; i++) y[p++]=i;
        F(i,0,n) if(sa[i]>=j) y[p++]=sa[i]-j;
        F(i,0,n) wv[i]=x[y[i]];
        F(i,0,m) wsf[i]=0;
        F(i,0,n) wsf[wv[i]]++;
        F(i,1,m) wsf[i]+= wsf[i-1];
        for(i=n-1; i>=0; i--) sa[--wsf[wv[i]]]=y[i];
        t=x, x=y, y=t;
        x[sa[0]]=0;
        for(p=1, i=1; i<n; i++)
            x[sa[i]]= cmp(y, sa[i-1], sa[i], j) ? p-1 : p++;
    }
}
void Getheight(int *r, int n)
{
    int i, j, k=0;
    FF(i,1,n) rankn[sa[i]]=i;
    F(i,0,n) {
        if(k) k--;
        else k=0;
        j=sa[rankn[i]-1];
        while(r[i+k]==r[j+k]) k++;
        height[rankn[i]]=k;
    }
}


int main()
{
    while(~scanf("%s%s", str, str1)) {
        int n=0, len=strlen(str);
        F(i,0,len) s[n++]= str[i]-a+1;
        s[n++]=28;
        len=strlen(str1);
        F(i,0,len) s[n++]= str1[i]-a+1;
        s[n]=0;    //把两个字符串并到一起,中间和结尾加上标识符

        Getsa(s, sa, n+1, 30);
        Getheight(s, n);
        int maxn=0, pos=0;
        len=strlen(str);
        F(i,2,n) if(height[i]>maxn) {   //找出一个height值最大并且i与i-1的sa值分别在两串字符中
            if(0<=sa[i-1] && sa[i-1]<len && len<sa[i])
                maxn=height[i];
            if(0<=sa[i] && sa[i]<len && len<sa[i-1])
                maxn=height[i];
        }
        printf("%d\n", maxn);
    }

    return 0;
}

 

POJ-2774 后缀数组基础题