POJ1226---Substrings(后缀数组+二分)

Description
You are given a number of case-sensitive strings of alphabetic characters, find the largest string X, such that either X, or its inverse can be found as a substring of any of the given strings.

Input
The first line of the input contains a single integer t (1 <= t <= 10), the number of test cases, followed by the input data for each test case. The first line of each test case contains a single integer n (1 <= n <= 100), the number of given strings, followed by n lines, each representing one string of minimum length 1 and maximum length 100. There is no extra white space before and after a string.

Output
There should be one line per test case containing the length of the largest string found.

Sample Input

2
3
ABCD
BCDFF
BRCD
2
rose
orchid

Sample Output

2
2

Source
Tehran 2002 Preliminary

把串,反串都连在一起,求后缀数组,然后二分,给后缀数组分组就行了

/*************************************************************************
    > File Name: POJ1226.cpp
    > Author: ALex
    > Mail: zchao1995@gmail.com 
    > Created Time: 2015年04月07日 星期二 16时45分07秒
 ************************************************************************/

#include <functional>
#include <algorithm>
#include <iostream>
#include <fstream>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <cstdlib>
#include <queue>
#include <stack>
#include <map>
#include <bitset>
#include <set>
#include <vector>

using namespace std;

const double pi = acos(-1.0);
const int inf = 0x3f3f3f3f;
const double eps = 1e-15;
typedef long long LL;
typedef pair <int, int> PLL;

int pos[22000];

class SuffixArray
{
    public:
        static const int N = 22000;
        int init[N];
        int X[N];
        int Y[N];
        int Rank[N];
        int sa[N];
        int height[N];
        int buc[N];
        int LOG[N];
        int dp[N][20];
        int size;
        bool vis[110];

        void clear()
        {
            size = 0;
        }

        void insert(int n)
        {
            init[size++] = n;
        }

        bool cmp(int *r, int a, int b, int l)
        {
            return (r[a] == r[b] && r[a + l] == r[b + l]);
        }

        void getsa(int m = 256) //m一般为最大值+1
        {
            init[size] = 0;
            int l, p, *x = X, *y = Y, n = size + 1;
            for (int i = 0; i < m; ++i)
            {
                buc[i] = 0;
            }
            for (int i = 0; i < n; ++i)
            {
                ++buc[x[i] = init[i]];
            }
            for (int i = 1; i < m; ++i)
            {
                buc[i] += buc[i - 1];
            }
            for (int i = n - 1; i >= 0; --i)
            {
                sa[--buc[x[i]]] = i;
            }
            for (l = 1, p = 1; l <= n && p < n; m = p, l *= 2)
            {
                p = 0;
                for (int i = n - l; i < n; ++i)
                {
                    y[p++] = i;
                }
                for (int i = 0; i < n; ++i)
                {
                    if (sa[i] >= l)
                    {
                        y[p++] = sa[i] - l;
                    }
                }
                for (int i = 0; i < m; ++i)
                {
                    buc[i] = 0;
                }
                for (int i = 0; i < n; ++i)
                {
                    ++buc[x[y[i]]];
                }
                for (int i = 1; i < m; ++i)
                {
                    buc[i] += buc[i - 1];
                }
                for (int i = n - 1; i >= 0; --i)
                {
                    sa[--buc[x[y[i]]]] = y[i];
                }
                int i;

                for (swap(x, y), x[sa[0]] = 0, p = 1, i = 1; i < n; ++i)
                { 
                    x[sa[i]] = cmp(y, sa[i - 1], sa[i], l) ? p - 1 : p++; 
                }
            }
        }

        void getheight()
        {
            int h = 0, n = size;
            for (int i = 0; i <= n; ++i)
            {
                Rank[sa[i]] = i;
            }
            height[0] = 0;
            for (int i = 0; i < n; ++i)
            {
                if (h > 0)
                {
                    --h;
                }
                int j =sa[Rank[i] - 1];
                for (; i + h < n && j + h < n && init[i + h] == init[j + h]; ++h);
                height[Rank[i] - 1] = h;
            }
        }   

        //预处理每一个数字的对数,用于rmq,常数优化
        void initLOG()
        {
            LOG[0] = -1;
            for (int i = 1; i < N; ++i)
            {
                LOG[i] = (i & (i - 1)) ? LOG[i - 1] : LOG[i - 1] + 1;
            }
        }

        void initRMQ()
        {
            initLOG();
            int n = size;
            int limit;
            for (int i = 0; i < n; ++i)
            {
                dp[i][0] = height[i];
            }
            for (int j = 1; j <= LOG[n]; ++j)
            {
                limit = (n - (1 << j));
                for (int i = 0; i <= limit; ++i)
                {
                    dp[i][j] = min(dp[i][j - 1], dp[i + (1 << j) - 1][j - 1]);
                }
            }
        }

        int LCP(int a, int b)
        {
            int t;
            a = Rank[a];
            b = Rank[b];
            if (a > b)
            {
                swap(a, b);
            }
--b;
            t = LOG[b - a + 1];
            return min(dp[a][t], dp[b - (1 << t) + 1][t]);
        }

        bool check(int k, int n)
        {
            int cnt = 1;
            memset(vis, 0, sizeof(vis));
            vis[pos[sa[1]]] = 1;
            for (int i = 1; i < size; ++i)
            {
                if (height[i] >= k)
                {
                    if (!vis[pos[sa[i + 1]]])
                    {
                        ++cnt;
                        vis[pos[sa[i + 1]]] = 1;
                    }
                }
                else
                {
                    if (cnt == n)
                    {
                        return 1;
                    }
                    memset(vis, 0, sizeof(vis));
                    vis[pos[sa[i + 1]]] = 1;
                    cnt = 1;
                }
            }
            return 0;
        }

        void solve(int n)
        {
            int l = 1, r = size, mid, ans = 0;
            while (l <= r)
            {
                mid = (l + r) >> 1;
                if (check(mid, n))
                {
                    l = mid + 1;
                    ans = mid;
                }
                else
                {
                    r = mid - 1;
                }
            }
            printf("%d\n", ans);
        }
}SA;

char str[120];

int main()
{
    int t;
    scanf("%d", &t);
    while (t--)
    {
        int n, maxs = 256, cnt = 0;
        SA.clear();
        scanf("%d", &n);
        if (n == 1)
        {
            scanf("%s", str);
            int len = strlen(str);
            printf("%d\n", len);
            continue;
        }
        for (int i = 1; i <= n; ++i)
        {
            scanf("%s", str);
            int len = strlen(str);
            for (int j = 0; j < len; ++j)
            {
                SA.insert((int)str[j]);
                pos[cnt++] = i;
            }
            SA.insert(maxs++);
            pos[cnt++] = 0;
            reverse(str, str + len);
            for (int j = 0; j < len; ++j)
            {
                SA.insert((int)str[j]);
                pos[cnt++] = i;
            }
            pos[cnt++] = 0;
            SA.insert(maxs++);
        }
        SA.getsa(maxs);
        SA.getheight();
        SA.solve(n);
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值