首页 > 代码库 > bzoj2946

bzoj2946

后缀数组+二分

中间加个字符,然后二分判断即可

技术分享
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 100010;
int n, top, k, tot, m, ans;
int a[N], sa[N], rank[N], temp[N], lcp[N], belong[N]; 
bool flag[6];
char c[N], s[N];
bool cp(int i, int j)
{
    if(rank[i] != rank[j]) return rank[i] < rank[j];
    int ri = i + k <= n ? rank[i + k] : -1;
    int rj = j + k <= n ? rank[j + k] : -1;
    return ri < rj;
}
void Sa()
{
    for(int i = 1; i <= n; ++i)
    {
        sa[i] = i;
        rank[i] = s[i];
    }
    for(k = 1; k <= n; k <<= 1)
    {
        sort(sa + 1, sa + n + 1, cp);
        temp[sa[1]] = 1;
        for(int i = 2; i <= n; ++i) temp[sa[i]] = temp[sa[i - 1]] + (cp(sa[i - 1], sa[i]));
        for(int i = 1; i <= n; ++i) rank[i] = temp[i];
    }
}
void Lcp()
{
    for(int i = 1; i <= n; ++i) rank[sa[i]] = i;
    int h = 0;
    for(int i = 1; i <= n; ++i)
    {
        int j = sa[rank[i] - 1];
        if(rank[i] <= 1) continue;
        if(h) --h;
        for(; i + h <= n && j + h <= n; ++h) if(s[i + h] != s[j + h]) break;
        lcp[rank[i] - 1] = h;        
    }
}
bool C(int x)
{
    for(int i = 1; i < n; ++i)
    {
        bool ff = true;
        if(lcp[i] >= x)
        {
            flag[belong[sa[i]]] = flag[belong[sa[i + 1]]] = true;
            for(int i = 1; i <= m; ++i) if(!flag[i]) 
            {
                ff = false;
                break;
            }
            if(ff) return true;
        }
        else memset(flag, false, sizeof(flag));
    }
    return false;
}
int main()
{
    scanf("%d", &m);
    for(int i = 1; i <= m; ++i)
    {
        scanf("%s", c + 1);
        for(int j = 1; j <= strlen(c + 1); ++j)
        {
            s[++n] = c[j];
            belong[n] = i;
        }
        s[++n] = # + i;
    }
    Sa();
    Lcp();
    int l = 0, r = 100000;
    while(r - l > 1)
    {
        int mid = (l + r) >> 1;
        if(C(mid)) l = ans = mid;
        else r = mid;
    }
    printf("%d\n", ans);
    return 0;
}
View Code

 

bzoj2946