【题目链接】
有一个结论:如果答案不是Infinity,那么最长回文子串只可能出现在一个串里,或者两个串拼接一次形成的串里。
那么我们枚举每个串的每个回文中心,对于剩下的不在回文串里的子串,去其他串里找一个拼接串,看能不能形成更大的回文串。
于是我们需要一个快速查询LCP的数据结构,选择后缀数组+ST表就可以了。
但是这样做复杂度还是比较高,于是我们考虑用图论模型优化。
先把单个串是回文串的情况特判掉。
对每个位置建两个点,分别代表当前位置前面/后面的剩余部分。如果可以剩余部分可以和其他串形成一个更大的回文串, 那么从这个剩余部分代表的点向目标点连边,边权为回文串长度。
对于这种情况:AB,A和B分别是个回文串,那么这种情况是Infinity,我们需要建立一个特殊节点,走到这个特殊节点的也算是Infinity。
当然,如果形成了一个环,也是Infinity。
否则答案就是最长路。
不太好说,看代码吧orz。
/* Telekinetic Forest Guard */ #include <cstdio> #include <cstring> #include <algorithm> using namespace std; typedef long long LL; const int maxn = 220005, maxm = 22000005; int n, head[maxn], cnt, bin[20], lg[maxn], len[maxn], slen[maxn]; struct _edge { int v, w, next; } g[maxm]; inline void addedge(int u, int v, int w) { g[cnt] = (_edge){v, w, head[u]}; head[u] = cnt++; } /* SA and ST */ int lc[maxn], rc[maxn], sa[maxn], rank[maxn], height[maxn], st[20][maxn]; int s[maxn], sym, m; int wa[maxn], wb[maxn], wv[maxn], tmp[maxn]; inline void getSA(int *r, int n, int m) { int *x = wa, *y = wb; for(int i = 0; i < m; i++) tmp[i] = 0; for(int i = 0; i < n; i++) tmp[x[i] = r[i]]++; for(int i = 1; i < m; i++) tmp[i] += tmp[i - 1]; for(int i = n - 1; i >= 0; i--) sa[--tmp[x[i]]] = i; for(int j = 1; j < n; j <<= 1) { int p = 0; for(int i = n - j; i < n; i++) y[p++] = i; for(int i = 0; i < n; i++) if(sa[i] >= j) y[p++] = sa[i] - j; for(int i = 0; i < m; i++) tmp[i] = 0; for(int i = 0; i < n; i++) tmp[wv[i] = x[y[i]]]++; for(int i = 1; i < m; i++) tmp[i] += tmp[i - 1]; for(int i = n - 1; i >= 0; i--) sa[--tmp[wv[i]]] = y[i]; swap(x, y); p = 1; x[sa[0]] = 0; for(int 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++; if(p >= n) break; m = p; } } inline void getHeight(int *r, int n) { int i, j, k; for(i = j = k = 0; i < n; height[rank[i++]] = k) for(k ? k-- : 0, j = sa[rank[i] - 1]; s[i + k] == s[j + k]; k++); } inline void getST(int n) { for(int i = 1; i <= n; i++) st[0][i] = height[i]; for(int i = 1; i <= lg[n]; i++) for(int j = 1; j + bin[i] - 1 <= n; j++) st[i][j] = min(st[i - 1][j], st[i - 1][j + bin[i - 1]]); } inline int stquery(int x, int y) { x = rank[x]; y = rank[y]; if(x > y) swap(x, y); x++; int k = lg[y - x + 1]; return min(st[k][x], st[k][y - bin[k] + 1]); } inline int query(int a, int x, int b, int y) { if(x > 0) a = lc[a] + x - 1; else a = rc[a] + (len[a] + x); if(y > 0) b = lc[b] + y - 1; else b = rc[b] + (len[b] + y); return stquery(a, b); } int S, T, T_; LL dis[maxn]; int du[maxn], q[maxn]; bool vis[maxn], inq[maxn]; inline bool loop(int x) { vis[x] = inq[x] = 1; for(int i = head[x]; ~i; i = g[i].next) { du[g[i].v]++; if(inq[g[i].v] || (!vis[g[i].v] && loop(g[i].v))) return 1; } return inq[x] = 0; } inline int getid(int x, int y) { if(x == 0) return S; if(x == -1) return T; if(y == 0 || y > len[x]) return T_; if(y > 0) return slen[x - 1] * 2 + y; return slen[x - 1] * 2 + len[x] - y; } inline void add(int a, int x, int b, int y, int w) { a = getid(a, x); b = getid(b, y); addedge(a, b, w); } char str[maxn]; int main() { bin[0] = 1; for(int i = 1; i < 20; i++) bin[i] = bin[i - 1] << 1; lg[0] = -1; for(int i = 1; i < maxn; i++) lg[i] = lg[i >> 1] + 1; sym = 26; scanf("%d", &n); for(int i = 1; i <= n; i++) { scanf("%s", str); len[i] = strlen(str); slen[i] = slen[i - 1] + len[i]; s[m++] = ++sym; lc[i] = m; for(int j = 0; j < len[i]; j++) s[m++] = str[j] - 'a' + 1; s[m++] = ++sym; rc[i] = m; for(int j = 0; j < len[i]; j++) s[m++] = str[len[i] - j - 1] - 'a' + 1; } getSA(s, m + 1, 300); for(int i = 0; i <= m; i++) rank[sa[i]] = i; getHeight(s, m); getST(m); S = 0; T = slen[n] * 2 + 10; T_ = T + 1; bool flag = 1; for(int i = 1; i <= n; i++) if(query(i, 0, i, -(len[i] + 1)) == len[i]) flag = 0; for(int i = 0; i < maxn; i++) head[i] = -1; LL ans = 0; for(int i = 1; flag && i <= n; i++) { for(int j = 1; j <= len[i]; j++) { int r = query(i, j, i, -j), l = min(j, len[i] - j + 1); ans = max(ans, (LL)r * 2 - 1); if(r == l) { if(j > len[i] - j + 1) add(0, 0, i, -(j - r), r * 2 - 1); else add(0, 0, i, j + r, r * 2 - 1); } } for(int j = 2; j <= len[i]; j++) { int r = query(i, j, i, -(j - 1)), l = min(j - 1, len[i] - j + 1); ans = max(ans, (LL)r * 2); if(r == l) { if(j - 1 > len[i] - j + 1) add(0, 0, i, -(j - 1 - r), r * 2); else add(0, 0, i, j + r, r * 2); } } add(0, 0, i, 1, 0); add(0, 0, i, -len[i], 0); for(int j = 1; j <= len[i]; j++) { int wf = 0, wr = 0; for(int k = 1; k <= n; k++) { int r = query(i, j, k, -len[k]); if(r == len[i] - j + 1) add(i, j, k, -(len[k] - r), r * 2); else if(r == len[k]) add(i, j, i, j + r, r * 2); else wf = max(wf, r * 2); r = query(i, -j, k, 1); if(r == j) add(i, -j, k, r + 1, r * 2); else if(r == len[k]) add(i, -j, i, -(j - r), r * 2); else wr = max(wr, r * 2); } if(wf > 0) add(i, j, -1, 0, wf); if(wr > 0) add(i, -j, -1, 0, wr); } } for(int i = 0; i < maxn; i++) du[i] = vis[i] = inq[i] = 0; if(!flag || loop(S) || vis[T_]) ans = -1; else { int h = 0, t = 0; q[t++] = S; for(int i = 0; i < maxn; i++) dis[i] = 0; while(h != t) { int u = q[h++]; for(int i = head[u]; ~i; i = g[i].next) { dis[g[i].v] = max(dis[g[i].v], dis[u] + g[i].w); ans = max(ans, dis[g[i].v]); if(!--du[g[i].v]) q[t++] = g[i].v; } } } if(!~ans) printf("Infinity\n"); else printf("%lld\n", ans); return 0; }