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; }