P3900 [湖南集训]图样图森破

P3900 [湖南集训]图样图森破

链接

分析:

  感觉像个暴力。

  可以枚举回文串的回文中心,即枚举一个串,枚举一个串的位置作为回文中心,然后求出这个串内的回文串的长度。

  此时如果回文串两端都没有到这个串的端点,那么以这个点作为回文中心的长度就直接算出来了。

  如果回文串的长度刚好是这个串的长度,那么INF。

  如果回文串一侧到了端点,那么枚举所有串,看看能否加到另一侧,来构成回文串。此过程记忆化搜索即可。

  复杂度$O(nL log nL)$

代码:

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<iostream>
#include<cmath>
#include<cctype>
#include<set>
#include<queue>
#include<vector>
#include<map>
using namespace std;
typedef long long LL;

inline int read() {
    int x=0,f=1;char ch=getchar();for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1;
    for(;isdigit(ch);ch=getchar())x=x*10+ch-'0';return x*f;
}

const int N = 200005;
int s[N], st[N], en[N], rnk[N], ht[N], sa[N], f[20][N], Log[N], t1[N], t2[N], c[N], bel[N], dp[N][2];
bool vis[N][2];
char tmp[N];
int n, m;

void getsa() {
    int *x = t1, *y = t2, m = 26, i;
    for (i = 1; i <= m; ++i) c[i] = 0;
    for (i = 1; i <= n; ++i) x[i] = s[i], c[x[i]] ++;
    for (i = 1; i <= m; ++i) c[i] += c[i - 1];
    for (i = n; i >= 1; --i) sa[c[x[i]] --] = i;
    for (int k = 1; k <= n; k <<= 1) {
        int p = 0;
        for (i = n - k + 1; i <= n; ++i) y[++p] = i;
        for (i = 1; i <= n; ++i) if (sa[i] > k) y[++p] = sa[i] - k;
        for (i = 1; i <= m; ++i) c[i] = 0;
        for (i = 1; i <= n; ++i) c[x[y[i]]] ++;
        for (i = 1; i <= m; ++i) c[i] += c[i - 1];
        for (i = n; i >= 1; --i) sa[c[x[y[i]]] --] = y[i];
        swap(x, y);
        p = 2;
        x[sa[1]] = 1;
        for (i = 2; i <= n; ++i) 
            x[sa[i]] = (y[sa[i]] == y[sa[i - 1]] && y[sa[i] + k] == y[sa[i - 1] + k]) ? p - 1 : p ++;
        if (p > n) break;
        m = p;
    }
    for (int i = 1; i <= n; ++i) rnk[sa[i]] = i;
    int k = 0;
    ht[1] = 0;
    for (int i = 1; i <= n; ++i) {
        if (rnk[i] == 1) continue;
        if (k) k --;
        int j = sa[rnk[i] - 1];
        while (i + k <= n && j + k <= n && s[i + k] == s[j + k]) k ++;
        ht[rnk[i]] = k;
    }
    Log[0] = -1;
    for (int i = 1; i <= n; ++i) Log[i] = Log[i >> 1] + 1;
    for (int i = 1; i <= n; ++i) f[0][i] = ht[i];
    for (int j = 1; j <= Log[n]; ++j) 
        for (int i = 1; i + (1 << j) - 1 <= n; ++i) 
            f[j][i] = min(f[j - 1][i], f[j - 1][i + (1 << (j - 1))]);
}
int query(int l,int r) {
    if (l == r) return 1e9;
    l = rnk[l], r = rnk[r];
    if (l > r) swap(l, r);
    l ++;
    int k = Log[r - l + 1];
    return min(f[k][l], f[k][r - (1 << k) + 1]);
}
int getlcp(int x,int y) {
    return min(query(x, n - y + 1), min(en[bel[x]] - x + 1, y - st[bel[y]] + 1));
}
void End() {
    puts("Infinity"); exit(0);
}
int dfs(int x,int t) {
    if (vis[x][t]) End();
    if (dp[x][t]) return dp[x][t];
    vis[x][t] = 1;
    if (!t) {
        for (int i = 1; i <= m; ++i) {
            int k = getlcp(x, en[i]), l = en[i] - k + 1, r = x + k - 1;
            if (r != en[bel[x]] && l != st[i]) dp[x][t] = max(dp[x][t], k * 2);
            else if (r == en[bel[x]] && l == st[i]) End();
            else if (r == en[bel[x]]) dp[x][t] = max(dp[x][t], k * 2 + dfs(l - 1, 1));
            else dp[x][t] = max(dp[x][t], k * 2 + dfs(r + 1, 0));
        }
    }
    else {
        for (int i = 1; i <= m; ++i) {
            int k = getlcp(st[i], x), l = x - k + 1, r = st[i] + k - 1;
            if (l != st[bel[x]] && r != en[i]) dp[x][t] = max(dp[x][t], k * 2);
            else if (l == st[bel[x]] && r == en[i]) End();
            else if (l == st[bel[x]]) dp[x][t] = max(dp[x][t], k * 2 + dfs(r + 1, 0));
            else dp[x][t] = max(dp[x][t], k * 2 + dfs(l - 1, 1));
        }
    }
    vis[x][t] = 0;
    return dp[x][t];
}
int main() {
    m = read();
    for (int i = 1; i <= m; ++i) {
        scanf("%s", tmp + 1);
        int len = strlen(tmp + 1);
        st[i] = n + 1;
        for (int j = 1; j <= len; ++j) s[++n] = tmp[j] - 'a' + 1, bel[n] = i;
        en[i] = n;
    }
    for (int i = 1; i <= n; ++i) s[i + n] = s[n - i + 1];
    n <<= 1;
    getsa();
    int ans = 0;
    for (int i = 1; i <= m; ++i) 
        ans = max(ans, max(dfs(st[i], 0), dfs(en[i], 1)));
    for (int i = 1; i <= m; ++i) {
        for (int j = st[i]; j <= en[i]; ++j) {
            int k = getlcp(j, j), l = j - k + 1, r = j + k - 1;
            if (l != st[i] && r != en[i]) ans = max(ans, k * 2 - 1);
            else if (l == st[i] && r == en[i]) End();
            else if (l == st[i]) ans = max(ans, k * 2 - 1 + dfs(r + 1, 0));
            else ans = max(ans, k * 2 - 1 + dfs(l - 1, 1));
        }
        for (int j = st[i]; j < en[i]; ++j) {
            int k = getlcp(j + 1, j), l = j - k + 1, r = j + k; // r = j + 1 + k - 1 !!!
            if (l != st[i] && r != en[i]) ans = max(ans, k * 2);
            else if (l == st[i] && r == en[i]) End();
            else if (l == st[i]) ans = max(ans, k * 2 + dfs(r + 1, 0));
            else ans = max(ans, k * 2 + dfs(l - 1, 1));
        }
    }
    cout << ans;
    return 0;
}
原文地址:https://www.cnblogs.com/mjtcn/p/10466434.html