• 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;
    }
  • 相关阅读:
    shell 操作钉钉机器人实现告警提醒
    谨慎 mongodb 关于数字操作可能导致类型及精度变化
    数据库如何应对保障大促活动
    SQL Server Alwayson架构下 服务器 各虚拟IP漂移监控告警的功能实现 -1(服务器视角)
    通过 Telegraf + InfluxDB + Grafana 快速搭建监控体系的详细步骤
    MySQL数据库Inception工具学习与测试 笔记
    MongoDB 中数据的替换方法实现 --类Replace()函数功能
    MongoDB 中的【加减乘除】运算
    MySQL索引设计需要考虑哪些因素?
    关于SQL Server 数据库归档的一些思考和改进
  • 原文地址:https://www.cnblogs.com/mjtcn/p/10466434.html
Copyright © 2020-2023  润新知