【题目链接】

有一个结论:如果答案不是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;
}

【BZOJ3654】图样图森破【最长路】【后缀数组】【ST表】【回文串】【LCP】相关推荐

  1. 后缀数组 ---- 2018~2019icpc焦作H题[后缀数组+st表+二分+单调栈]

    题目链接 题目大意: 给出nnn个数,定义f[l,r]f[l,r]f[l,r]表示 区间[l,r][l,r][l,r]的最大值,求所有 子区间的最大值的和,要求相同的子区间只能算一次 比如数列 5 6 ...

  2. 【BZOJ4310】跳蚤,后缀数组+ST表求LCP+二分答案

    Time:2016.05.26 Author:xiaoyimi 转载注明出处谢谢 传送门 思路: 首先要求出不同子串的个数 有这样一个性质 一个串中不同子串的总数=∑(len-height[i]-sa ...

  3. [luoguP2463] [SDOI2008]Sandy的卡片(后缀数组 + st表)

    传送门 很容易想到,题目中的相同是指差分数组相同. 那么可以把差分数组连起来,中间加上一个没有出现过的且字典序小的数 双指针移动,用st表维护height数组中的最小值. 当然用单调队列应该也可以且更 ...

  4. 最长回文串--动态规划

    最长回文串–动态规划 参考:https://writings.sh/post/algorithm-longest-palindromic-substring class Solution {publi ...

  5. 字符串相关处理kmp,前缀数,后缀树,后缀数组,最长回文串,最长重复字串,最长非重复字串

    1. 最长回文串 一般用后缀数组或者后缀树可以解决, 用此方法:http://blog.csdn.net/v_july_v/article/details/6897097 预处理后缀树,使得查询LCA ...

  6. 求最长回文串-从动态规划到马拉车之路(下)

    预备知识: (1)在一个数轴上有两点i和j(i<=j)关于点m对称,那么有 i = 2m-j: 证明: 因为 i<=j 且 i 和 j 关于 m 对称,那么有 (i + j)/ 2 = m ...

  7. 求最长回文串-从动态规划到马拉车之路(上)

    要解决的问题: 给定一个字符串,要求求出这个字符串中的最长的回文串子串. 例子: cbddba的最长回文子串为 bddb cbdedba的最长回文子串为dbedb 由上面的例子可以看到,在考虑回文子串 ...

  8. manacher算法----O(n)最长回文串

    manacher算法----O(n)最长回文串 分类:字符串 (126)  (0)  举报  收藏 manacher的时间复杂度为O(n),后缀数组好像可以处理O(nlogn),但是有些变态题目可能卡 ...

  9. [国家集训队]最长双回文串 manacher

    ---题面--- 题解: 首先有一个直观的想法,如果我们可以求出对于位置i的最长后缀回文串和最长前缀回文串,那么我们枚举分界点然后合并前缀和后缀不就可以得到答案了么? 所以我们的目标就是求出这两个数列 ...

  10. HYSBZ - 2565 最长双回文串(回文自动机)

    题目链接:点击查看 题目大意:给出一个字符串 s ,求最长双回文子串,题目规定最长双回文子串 t 可以拆成左右两部分,满足两部分都是回文串 题目分析:一开始读错题了,以为是双回文串本身也需要是回文串, ...

最新文章

  1. AD,proteus操作
  2. 学Java发展前景好的三个原因
  3. mysqldump: Got error: 1449
  4. Android TimeAnimator
  5. hadoop 单节点安装
  6. Pattern类与Matcher方法的验证
  7. AndroidStudio安卓原生开发_UI高级_自定义主题和样式---Android原生开发工作笔记129
  8. 空间波(space wave)
  9. Android sdcard读写权限问题之中的一个
  10. COJ 0967 WZJ的数据结构(负三十三)
  11. svn合并分支到主干,工具操作
  12. 宏基ec471g黑苹果_【图片】简单安装黑苹果,老爷车宏基E1-471G完整度90%,显卡声卡成功驱动【2_黑苹果吧】_百度贴吧...
  13. Word插入高分辨率图片无法显示
  14. gradle教程java_Gradle教程系列 ——Gradle基本语法
  15. 华师大计算机在线测试,华东师大:180道心理测试题面试免费师范生
  16. 逆火软件测试工资,世界级人体工学设计:HyperX Pulsefire FPS逆火鼠标评测
  17. 如何让木马克星能在win2003上免费使用
  18. 2018-2019 起风了,唯有努力生存
  19. UNILUX频闪仪维修LITH-O-LIGHT-5频闪灯LOL-5/LOL-10
  20. VueUse 中文文档:Components 组件

热门文章

  1. 理论篇-Linux---RAID磁盘阵列与阵列卡
  2. 计算机网络的未来的发展前景,浅谈计算机网络的未来发展趋势
  3. uni-app -- 选择图片、上传图片
  4. 根据excel列动态创建mysql表,excel动态生成表格数据/EXCEL根据表2数据自动生成表1内容?...
  5. 数商云跨境电商平台解决方案
  6. 哈希碰撞,改变世界的原力
  7. CSS+DIV-网页变幻(HTML篇)
  8. A,B,C,D,E五个人在某天夜里去捕鱼
  9. 无限的可能的投资回报率
  10. linux下WMB通过ODBC连接数据库