title

BZOJ 3654

LUOGU 3900

Description

长者有一个字符串集合 \(S\) ,此处集合的概念与数学中的集合不同,其中可以含有重复的元素。初始时 \(S\) 包含 \(n\) 个字符串 \(s_1,s_2,⋯,s_n\) 。有下面两种操作:

  • 向 \(S\) 中加入一个已经存在于 \(S\) 中的字符串。

  • 从 \(S\) 中选出两个字符串,将这两个字符串拼接得到的字符串加入集合 \(S\) 。

长者想要知道,进行任意多次操作之后,在 \(S\) 中的所有字符串中,最长的回文子串可以有多长?长者毕竟身经百战,他发现长度可以是无穷大,这时你需要输出 Infinity

analysis

原来题目意思是 too young too simple ,哈哈。

回文串给人的感觉要用 \(manacher\) ,但其实这题是让构造最长回文串,所以是不能用 \(manacher\) 的。

这就可以用 \(SA\) 来每次提取 \(LCP\) 来进行构造了。

大致流程是这样的:

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

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

  2. 如果回文串的长度刚好是这个串的长度,那么 \(INF\) 。

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

时间复杂度 \(O(nL\log nL)\) 。(代码量有些大,逃)

code

#include<bits/stdc++.h>const int maxn=2e5+10;namespace IO
{char buf[1<<15],*fs,*ft;inline char getc() { return (ft==fs&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),ft==fs))?0:*fs++; }template<typename T>inline void read(T &x){x=0;T f=1, ch=getchar();while (!isdigit(ch) && ch^'-') ch=getchar();if (ch=='-') f=-1, ch=getchar();while (isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48), ch=getchar();x*=f;}char Out[1<<24],*fe=Out;inline void flush() { fwrite(Out,1,fe-Out,stdout); fe=Out; }template<typename T>inline void write(T x,char str){if (!x) *fe++=48;if (x<0) *fe++='-', x=-x;T num=0, ch[20];while (x) ch[++num]=x%10+48, x/=10;while (num) *fe++=ch[num--];*fe++=str;}
}using IO::read;
using IO::write;template<typename T>inline bool chkMin(T &a,const T &b) { return a>b ? (a=b, true) : false; }
template<typename T>inline bool chkMax(T &a,const T &b) { return a<b ? (a=b, true) : false; }
template<typename T>inline T min(T a,T b) { return a<b ? a : b; }
template<typename T>inline T max(T a,T b) { return a>b ? a : b; }int Log2[maxn];
inline void calcLog2()
{for (int i=2; i<maxn; ++i) Log2[i]=Log2[i>>1]+1;
}struct SuffixArray
{int c[maxn],x[maxn],y[maxn],sa[maxn],n,m;int s[maxn];inline void init(){memset(this,0,sizeof(SuffixArray));}inline void build_sa(){memset(c,0,sizeof(c));for (int i=1; i<=n; ++i) ++c[x[i]=s[i]];for (int i=2; i<=m; ++i) c[i]+=c[i-1];for (int i=n; i>=1; --i) sa[c[x[i]]--]=i;for (int k=1; k<=n; k<<=1){int num=0;for (int i=n-k+1; i<=n; ++i) y[++num]=i;for (int i=1; i<=n; ++i) if (sa[i]>k) y[++num]=sa[i]-k;memset(c,0,sizeof(c));for (int i=1; i<=n; ++i) ++c[x[i]];for (int i=2; i<=m; ++i) c[i]+=c[i-1];for (int i=n; i>=1; --i) sa[c[x[y[i]]]--]=y[i],y[i]=0;std::swap(x,y);x[sa[1]]=num=1;for (int i=2; i<=n; ++i) x[sa[i]]=(y[sa[i]]==y[sa[i-1]] && y[sa[i]+k]==y[sa[i-1]+k]) ? num : ++num;if (num==n) break;m=num;}}int rank[maxn],height[maxn];inline void build_height(){int k=0;for (int i=1; i<=n; ++i) rank[sa[i]]=i;for (int i=1; i<=n; ++i){if (rank[i]==1) continue;//if (k) --k;int j=sa[rank[i]-1];//while (j+k<=n && i+k<=n && s[i+k]==s[j+k]) ++k;height[rank[i]]=k;}}int st[maxn][25];inline void calcst(){for (int i=1; i<=n; ++i) st[i][0]=height[i];for (int i=1; i<=20; ++i)for (int j=1; j+(1<<i)<=n; ++j) st[j][i]=min(st[j][i-1],st[j+(1<<i-1)][i-1]);}inline int query_lcp(int x,int y){x=rank[x],y=rank[y];if (x>y) std::swap(x,y);int t=Log2[y-x];return min(st[x+1][t],st[y-(1<<t)+1][t]);}
} SA;int pre[maxn],suf[maxn],bel[maxn];
inline int lcp(int x,int y)
{return min(SA.query_lcp(x,SA.n-y+1),min(suf[bel[x]]-x+1,y-pre[bel[y]]+1));
}inline void End() { puts("Infinity"); exit(0); }int f[maxn][2],m;
bool vis[maxn][2];
inline int dfs(int x,int t)
{if (vis[x][t]) End();if (f[x][t]) return f[x][t];vis[x][t]=1;if (!t){for (int i=1; i<=m; ++i){int k=lcp(x,suf[i]), l=suf[i]-k+1, r=x+k-1;if (r^suf[bel[x]] && l^pre[i]) chkMax(f[x][t],k<<1);else if (r==suf[bel[x]] && l==pre[i]) End();else if (r==suf[bel[x]]) chkMax(f[x][t],(k<<1)+dfs(l-1,1));else chkMax(f[x][t],(k<<1)+dfs(r+1,0));}}else{for (int i=1; i<=m; ++i){int k=lcp(pre[i],x), l=x-k+1, r=pre[i]+k-1;if (l^pre[bel[x]] && r^suf[i]) chkMax(f[x][t],k<<1);else if (l==pre[bel[x]] && r==suf[i]) End();else if (l==pre[bel[x]]) chkMax(f[x][t],(k<<1)+dfs(r+1,0));else chkMax(f[x][t],(k<<1)+dfs(l-1,1));}}vis[x][t]=0;return f[x][t];
}char ch[maxn];
int main()
{calcLog2();read(m);SA.init(), SA.m=26;for (int i=1; i<=m; ++i){scanf("%s",ch+1);int len=strlen(ch+1);pre[i]=SA.n+1;for (int j=1; j<=len; ++j) SA.s[++SA.n]=ch[j]-'a'+1, bel[SA.n]=i;suf[i]=SA.n;}for (int i=1; i<=SA.n; ++i) SA.s[i+SA.n]=SA.s[SA.n-i+1];SA.n<<=1;SA.build_sa(), SA.build_height(), SA.calcst();int ans=0;for (int i=1; i<=m; ++i) chkMax(ans,max(dfs(pre[i],0),dfs(suf[i],1)));for (int i=1; i<=m; ++i){for (int j=pre[i]; j<=suf[i]; ++j){int k=lcp(j,j), l=j-k+1, r=j+k-1;if (l^pre[i] && r^suf[i]) chkMax(ans,(k<<1)-1);else if (l==pre[i] && r==suf[i]) End();else if (l==pre[i]) chkMax(ans,(k<<1)-1+dfs(r+1,0));else chkMax(ans,(k<<1)-1+dfs(l-1,1));}for (int j=pre[i]; j<suf[i]; ++j){int k=lcp(j+1,j), l=j-k+1, r=j+k;if (l^pre[i] && r^suf[i]) chkMax(ans,k<<1);else if (l==pre[i] && r==suf[i]) End();else if (l==pre[i]) chkMax(ans,(k<<1)+dfs(r+1,0));else chkMax(ans,(k<<1)+dfs(l-1,1));}}write(ans,'\n');IO::flush();return 0;
}

转载于:https://www.cnblogs.com/G-hsm/p/11436821.html

BZOJ 3654: [湖南集训]图样图森破 SA相关推荐

  1. bzoj 3653 [湖南集训]谈笑风生

    题目描述 设 T 为一棵有根树,我们做如下的定义: • 设 a 和 b 为 T 中的两个不同节点.如果 a 是 b 的祖先,那么称"a 比 b 不知道高明到哪里去了". • 设 a ...

  2. 洛谷 - P3899 [湖南集训]谈笑风生(dfs序+主席树/二维数点)

    题目链接:点击查看 题目大意:设 TTT 为一棵有根树,我们做如下的定义: 设 aaa 和 bbb 为 TTT 中的两个不同节点.如果 aaa 是 bbb 的祖先,那么称"aaa 比 bbb ...

  3. P3899 [湖南集训]谈笑风生(线段树合并)

    P3899 [湖南集训]谈笑风生 给定一颗以111号节点为根的树,如果a≠ba \neq ba​=b,且aaa是bbb的祖先,则aaa比bbb更厉害,如果a≠ba \neq ba​=b,且dis( ...

  4. P3899 [湖南集训]谈笑风生

    P3899 [湖南集训]谈笑风生 题目描述 Solution 我们考虑离线询问,将询问放在相对应的子树ppp中计算答案. 显然a,b,ca,b,ca,b,c的位置关系有两种情况: bbb是aaa的祖先 ...

  5. P3899 [湖南集训]更为厉害(线段树合并、长链剖分、二维数点)

    P3899 [湖南集训]更为厉害 若 deepb<deepa\text{deep}_b<\text{deep}_adeepb​<deepa​:c 在点 a 的子树中,根据乘法原理计算 ...

  6. OI生涯回忆录(Part7:至高一湖南集训Day3)

    (卅一)联赛惨案 NOIP结束了,自然我是要回班上课的. 王晓光这边说着尽量在沟通让我和李佳实尽快脱产,然而并不知道什么时候能办完.... 转过来这个周中就开始了各种山寨数据的测试,学军自己出的.杭二 ...

  7. UOJ #268 BZOJ 4732 [清华集训2016]数据交互 (树链剖分、线段树)

    题目链接 (BZOJ) https://www.lydsy.com/JudgeOnline/problem.php?id=4732 (UOJ) http://uoj.ac/problem/268 题解 ...

  8. BZOJ.4738.[清华集训2016]汽水(点分治 分数规划)

    BZOJ UOJ 记\(val_i\)是每条边的边权,\(s\)是边权和,\(t\)是经过边数,\(k\)是给定的\(k\). 在点分治的时候二分答案\(x\),设\(|\frac st-k|=x\) ...

  9. [湖南集训]更为厉害 树上主席树-以树深度为下下标建立主席树

    题意题解: 首先对于树上某个点a来说,假设点b是a的祖先(也就是在a的上面),那么答案很好计算,也就是min(k,dep[a]−1)∗(size[a]−1)min(k,dep[a]-1)*(size[ ...

  10. UOJ #277 BZOJ 4739 [清华集训2016]定向越野 (计算几何、最短路)

    手动博客搬家: 本文发表于20181208 14:39:01, 原地址https://blog.csdn.net/suncongbo/article/details/84891710 哇它居然显示出图 ...

最新文章

  1. 【C】浅谈strcpy
  2. [转载]TFS测试管理
  3. 64位大内存虚拟机Page File的存放位置
  4. 数据竞赛:记录3天进入比赛Top3%的全过程
  5. 超好:web app变革之rem
  6. leetcode66. 加一
  7. 安装redis,执行make test时遇到You need tcl 8.5 or newer in order to run the Redis test
  8. Theano 中文文档 0.9 - 6. 更新Theano
  9. IoT、3D 扫描抢救巴黎圣母院!
  10. 传说中的神器: shared_ptr/weak_ptr/scoped_ptr
  11. html不同类别的列表设置,HTML --列表
  12. Py之Scipy:Scipy库(高级科学计算库)的简介、安装、使用方法之详细攻略
  13. 三种刷写LEDE等软路由固件的方法
  14. 现代信号处理——自适应滤波器(LMS自适应滤波器)
  15. 常州大学移动宽带上网助手——安装包v1.4
  16. 建立U盘免疫病毒文件
  17. 百度世界2012大会:百度云“七种武器”详解
  18. appbase 和docbase
  19. ORACLE EBS常用表
  20. 公众号如何用微信红包吸粉而不被封号?实战24天10万粉

热门文章

  1. 拼多多软件测试开发,拼多多事件对我们业务测试的启发
  2. vue 的ui组件库
  3. linux看温度命令,linux查看cpu温度命令
  4. 为什么python打不开_Python打不开.py文件
  5. python opencv rgb值判断红色_Python-opencv实现红绿两色识别操作
  6. html5 怎么插指南针,HTML5 App实战(5):指南针
  7. 时序分析 27 - 时序预测 格兰杰因果关系(上) 理论知识
  8. 如何衡量一篇英语作文词汇丰富度?
  9. 产品设计(1):开源产品设计工具pencil
  10. 电脑变慢,电脑突然变慢怎么办 电脑卡死原因和解决方法