[BZOJ 3654] 图样图森破

这里写图片描述

Solution :
把每个串和它们的反转拉一起求一个后缀数组,然后枚举回文串的中心,往回文串两边尽可能添加串,这个过程可以记忆化,如果转移中发现了环说明长度可以无限大。

吐槽:刚开始写的RMQ有点问题,怒改为暴力求lcp然后就A了…10s…..这题好 但是数据有待加强…….

#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <bitset>
#include <cmath>
#include <ctime>
#include <algorithm>
#include <iterator>
#include <vector>
#include <queue>
#include <set>
#include <map>

#define rep(i, x, y) for (int i = (x), _ = (y); i <= _; ++i)
#define down(i, x, y) for (int i = (x), _ = (y); i >= _; --i)
#define x first
#define y second
#define LX_JUDGE

using namespace std;
typedef long long LL;

template<typename T> inline void upMax(T & x, T y) { x < y ? x = y : 0; }
template<typename T> inline void upMin(T & x, T y) { x > y ? x = y : 0; }

template<typename T>
inline void read(T & x)
{
    char c;
    while ((c = getchar()) < '0' || c > '9') ;
    for (x = c - '0'; (c = getchar()) >= '0' && c <= '9'; x = x * 10 + c - '0') ;
}

const LL inf = 1e15;
const int N = 2e5 + 3e4;

namespace suffixArray
{
    int Sa[N], Rank[N], height[N];
    int mn[N][19], Log[N], tot;

    void suffixDa(char * r, int n, int m)
    {
        static int ws[N];
        int i, j, p, *x = Rank, *y = height;
        tot = n;

        memset(ws, 0, sizeof(int) * m);
        for (i = 0; i < n; ++i)
            ++ws[x[i] = r[i]];
        for (i = 1; i < m; ++i)
            ws[i] += ws[i - 1];
        for (i = n - 1; ~i; --i)
            Sa[--ws[x[i]]] = i;
        for (j = p = 1; p < n; j <<= 1, m = p)
        {
            for (p = 0, i = n - j; i < n; ++i)
                y[p++] = i;
            for (i = 0; i < n; ++i) if (Sa[i] >= j)
                y[p++] = Sa[i] - j;
            memset(ws, 0, sizeof(int) * m);
            for (i = 0; i < n; ++i)
                ++ws[x[i]];
            for (i = 1; i < m; ++i)
                ws[i] += ws[i - 1];
            for (i = n - 1; ~i; --i)
                Sa[--ws[x[y[i]]]] = y[i];
            swap(x, y);
            x[Sa[0]] = 0, p = 1;
            for (i = 1; i < n; ++i)
                x[Sa[i]] = (y[Sa[i - 1]] == y[Sa[i]] && y[Sa[i - 1] + j] == y[Sa[i] + j]) ? p - 1 : p++;
        }
        for (i = 0; i < n; ++i)
            Rank[Sa[i]] = i;
        for (i = p = 0; i < n - 1; ++i)
        {
            p ? --p : 0;
            j = Sa[Rank[i] - 1];
            while (r[i + p] == r[j + p]) 
                ++p;
            height[Rank[i]] = p;
        }
        height[0] = height[1] = height[n] = 0;

        rep (i, 2, n)
            Log[i] = Log[i >> 1] + 1;

        rep (i, 0, n - 1) 
            mn[i][0] = height[i];

        rep (i, 0, Log[n] - 1)
        {
            rep (j, 0, n - (1 << (i + 1)) + 1)
                mn[j][i + 1] = min(mn[j][i], mn[j + (1 << i)][i]);
        }
    }

    int Lcp(int x, int y)
    {
        if (x == y)
            return tot - x;
        x = Rank[x], y = Rank[y];
        if (x > y)
            swap(x, y);
        int k = Log[y - x];
        return min(mn[x + 1][k], mn[y - (1 << k) + 1][k]);
    }
}

char str[N];
int belong[N], start[211], last[211];
int n, m;

LL f[N];
bool ins[N];

LL calc(int x)
{
    using suffixArray::Lcp;

    if (str[x] < 'a')
        x = m;

    if (ins[x]) 
        return inf;
    else if (f[x] > 0) 
        return f[x];

    LL &ans = f[x];
    ins[x] = 1;

    if (x == m)
    {
        rep (i, 1, n + n)
            upMax(ans, calc(start[i]));
    }
    else 
    {
        int p = belong[x];

        rep (j, (p <= n ? n + 1 : 1), (p <= n ? n + n : n))
        {
            int t = min(Lcp(x, start[j]), min(last[p] - x, last[j] - start[j]));
            if (x + t == last[p])
                upMax(ans, calc(start[j] + t) + t * 2);
            else if (start[j] + t == last[j])
                upMax(ans, calc(x + t) + t * 2);
            else 
                upMax(ans, 2ll * t);
        }
    }

    upMax(ans, 0ll), upMin(ans, inf);
    ins[x] = 0;

    return ans;
}

int main()
{
#ifdef LX_JUDGE
    freopen("in.txt", "r", stdin);
#endif
    read(n);

    rep (i, 1, n)
    {
        scanf("%s", str + m);
        start[i] = m;
        while (str[m])
            belong[m++] = i;
        last[i] = m;
        str[m++] = 'a' - 1;
    }

    int cur = 0;

    rep (i, n + 1, n + n)
    {
        start[i] = m;
        while (str[cur] >= 'a')
        {
            belong[m] = i;
            str[m++] = str[cur++];
        }
        last[i] = m;
        str[m++] = str[cur++];
        reverse(str + start[i], str + last[i]);
    }

    str[m++] = 0;
    suffixArray::suffixDa(str, m, 128);

    memset(f, -1, sizeof(f));

    LL ans = calc(m);

    rep (i, 1, n)
    {
        using suffixArray::Lcp;
        for (int j = start[i], k = last[i + n] - 1; j < last[i]; ++j, --k)
        {
            int tmp = min(Lcp(j, k), min(last[i] - j, last[i + n] - k));

            if (j + tmp == last[i])
                upMax(ans, calc(k + tmp) + 2 * tmp - 1);
            else if (k + tmp == last[i + n])
                upMax(ans, calc(j + tmp) + 2 * tmp - 1);
            else 
                upMax(ans, 2ll * tmp - 1);
        }
        for (int j = start[i] + 1, k = last[i + n] - 1; j < last[i]; ++j, --k)
        {
            int tmp = min(Lcp(j, k), min(last[i] - j, last[i + n] - k));

            if (j + tmp == last[i])
                upMax(ans, calc(k + tmp) + tmp * 2);
            else if (k + tmp == last[i + n])
                upMax(ans, calc(j + tmp) + tmp * 2);
            else 
                upMax(ans, 2ll * tmp);
        }
    }

    ans < inf ? printf("%lld\n", ans) : puts("Infinity");

    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值