【题目】
原题地址
给定一个字符串集合SSS,每次可以向SSS中加入一个已经存在于SSS中的字符串或者从SSS中选出两个字符串,将它们拼接后得到的字符串加入SSS。∣S∣≤100,∣Si∣≤1000|S|\leq 100,|S_i|\leq 1000∣S∣≤100,∣Si​∣≤1000

【解题思路】
第一眼看肯定先判掉单个串是回文串,然后就陷入了沉思。
分析了很久以后看出来,如果答案不是INFINFINF,那么最长回文子串只可能出现在一个串里,或者出现在两个串拼接一次形成的串里(还有可能是三个呢)。
然后就有了一个很naive\text{naive}naive的想法:枚举两个串拼接,再枚举一个回文中心点,这样我们应该只需要用后缀数组的O(1)LCPO(1)\text{LCP}O(1)LCP瞎搞就行了。这个我们当然是可以做的了,不过复杂度是O(n2L+nLlog⁡(nL))O(n^2L+nL\log (nL))O(n2L+nLlog(nL))的,十分不优美。

不过这个做法比QT的什么鬼图论好搞多了,我们直接暴力算了。

等等,还有一个问题是要看能不能长度无限,不过这个问题也很好解决吧,其实本质上来说,就是匹配不能形成一个环。
于是我们设fi,0f_{i,0}fi,0​表示iii这个位置向后能扩展到的回文串最长是多少,fi,1f_{i,1}fi,1​表示向前。仍然像上面一样枚举中心点,当超过长度枚举串拼接,不同的是,我们用记忆化搜索来判断拼接后是否会产生环的转移,这样应该可以省去很多特判。

嗯,卡一卡就能过了。
然后跑得巨快,是我复杂度算错了?
顺带一提,以后写代码一定要开Wall。
update:
经提醒发现答案还可能由三个串拼在一起,但是记忆化来做可以保证正确性。

【参考代码】

#include<bits/stdc++.h>
using namespace std;const int N=2e5+10;
int n,m,ans;
int bl[N],st[N],en[N],s[N],f[N][2];
bool vis[N][2],bo[N][2];
char ss[N];namespace SA
{int len,rk[N],hi[N],fc[30],Log[N],h[22][N];int wa[N],wb[N],wx[N],wy[N],sa[N];bool cmp(int *r,int a,int b,int l){return r[a]==r[b] && r[a+l]==r[b+l];}void getsa(int *r,int n,int m){int *x=wa,*y=wb,*t,i,j,p;for(i=0;i<m;++i) wx[i]=0;for(i=0;i<n;++i) wx[x[i]=r[i]]++;for(i=1;i<m;++i) wx[i]+=wx[i-1];for(i=n-1;~i;--i) sa[--wx[x[i]]]=i;for(j=1,p=1;p<n;j<<=1,m=p){for(p=0,i=n-j;i<n;++i) y[p++]=i;for(i=0;i<n;++i) if(sa[i]>=j) y[p++]=sa[i]-j;for(i=0;i<m;++i) wx[i]=0;for(i=0;i<n;++i) wx[wy[i]=x[y[i]]]++;for(i=1;i<m;++i) wx[i]+=wx[i-1];for(i=n-1;~i;--i) sa[--wx[wy[i]]]=y[i];for(t=x,x=y,y=t,p=1,x[sa[0]]=0,i=1;i<n;++i) x[sa[i]]=cmp(y,sa[i-1],sa[i],j)?p-1:p++;}}void adjust(int n){for(int i=1;i<=n;++i) sa[i]++;for(int i=n;i;--i) rk[i]=rk[i-1];sa[0]=rk[0]=hi[0]=0;}void getheight(int *r,int n){int i,j,k=0;for(i=1;i<n;++i) rk[sa[i]]=i;for(i=0;i<n;hi[rk[i++]]=k)for(k?k--:0,j=sa[rk[i]-1];r[i+k]==r[j+k];++k);//adjust(len);fc[0]=1;for(int i=1;i<20;++i) fc[i]=fc[i-1]<<1;for(int i=2;i<n;++i) Log[i]=Log[i>>1]+1;for(int i=1;i<n;++i) h[0][i]=hi[i];//cerr<<n<<endl;for(int j=1;j<19;++j) for(int i=1;i+fc[j]-1<n;++i)h[j][i]=min(h[j-1][i],h[j-1][i+fc[j-1]]);}void buildSA(){len=m+1;getsa(s,len,30);getheight(s,len);}int calc(int x,int y){int t=Log[y-x+1];//printf("%d %d\n",h[t][x],h[t][y-fc[t]+1]);return min(h[t][x],h[t][y-fc[t]+1]);}int lcp(int x,int y){if(x==y) return N;//printf("lcp:%d %d %d %d %d\n",x,y,rk[x],rk[y],calc(x+1,y));if((x=rk[x])>(y=rk[y])) swap(x,y);//cerr<<x<<" "<<y<<endl;return calc(x+1,y);}int query(int x,int y){//printf("%d %d %d %d %d %d\n",m,x,y,min(lcp(x,m-y-1),min(en[bl[x]]-x,y-st[bl[y]]+1)),lcp(x,m-y-1),min(en[bl[x]]-x,y-st[bl[y]])+1);return min(lcp(x,m-y-1),min(en[bl[x]]-x,y-st[bl[y]])+1);}void output(){for(int i=0;i<=len;++i) printf("%d ",sa[i]); puts("");for(int i=0;i<=len;++i) printf("%d ",rk[i]); puts("");for(int i=0;i<=len;++i) printf("%d ",hi[i]); puts("");}
}
using SA::buildSA;
using SA::query;void putINF(){puts("Infinity");exit(0);}
int dfs(int x,int p)
{if(vis[x][p]) putINF();if(bo[x][p]) return f[x][p];vis[x][p]=bo[x][p]=1;int &res=f[x][p];if(!p){for(int i=1;i<=n;++i){int t=query(x,en[i]),a=x+t-1,b=en[i]-t+1;if(a<en[bl[x]] && b>st[i]) res=max(res,t*2);else if(a==en[bl[x]] && b==st[i]) putINF();else if(a==en[bl[x]]) res=max(res,t*2+dfs(b-1,1));else res=max(res,t*2+dfs(a+1,0));}} else{for(int i=1;i<=n;++i){//cerr<<i<<" "<<st[i]<<" "<<x;int t=query(st[i],x),a=x-t+1,b=st[i]+t-1;if(a>st[bl[x]] && b<en[i]) res=max(res,t*2);else if(a==st[bl[x]] && b==en[i]) putINF();else if(a==st[bl[x]]) res=max(res,t*2+dfs(b+1,0));else res=max(res,t*2+dfs(a-1,1));}}vis[x][p]=0; return res;
}int main()
{#ifndef ONLINE_JUDGEfreopen("BZOJ3654.in","r",stdin);freopen("BZOJ3654.out","w",stdout);
#endifscanf("%d",&n);for(int i=1,l;i<=n;++i){scanf("%s",ss);l=strlen(ss);st[i]=m;for(int j=0;j<l;++j) bl[m]=i,s[m++]=ss[j]-'a'+1;en[i]=m-1;//printf("%d %d\n",st[i],en[i]);}m<<=1;for(int i=0,j=m-1;i<j;++i,--j) s[j]=s[i],bl[j]=bl[i];SA::buildSA();//SA::output();for(int i=1;i<=n;++i) ans=max(ans,max(dfs(st[i],0),dfs(en[i],1)));
//printf("%d\n",ans);for(int i=1;i<=n;++i){for(int j=st[i];j<=en[i];++j){int t=query(j,j),a=j-t+1,b=j+t-1;if(a>st[i] && b<en[i]) ans=max(ans,t*2-1);else if(a==st[i] && b==en[i]) putINF();else if(a==st[i]) ans=max(ans,t*2-1+dfs(b+1,0));else ans=max(ans,t*2-1+dfs(a-1,1));}//oddfor(int j=st[i];j<en[i];++j){int t=query(j+1,j),a=j-t+1,b=j+t;if(a>st[i] && b<en[i]) ans=max(ans,t*2);else if(a==st[i] && b==en[i]) putINF();else if(a==st[i]) ans=max(ans,t*2+dfs(b+1,0));else ans=max(ans,t*2+dfs(a-1,1));}//even}printf("%d\n",ans);return 0;
}

【后缀数组+???】BZOJ3654 图样图森破相关推荐

  1. 寻找一个字符串的重复子串 后缀数组

    什么是后缀数组 令字符串 S=S[1]S[2]...S[n]S=S[1]S[2]...S[n]{\displaystyle S=S[1]S[2]...S[n]} , S[i,j]S[i,j]{\dis ...

  2. 【2012百度之星/资格赛】H:用户请求中的品牌 [后缀数组]

    时间限制: 1000ms 内存限制: 65536kB 描述 馅饼同学是一个在百度工作,做用户请求(query)分析的同学,他在用户请求中经常会遇到一些很奇葩的词汇.在比方说"johnsonj ...

  3. Boring counting HDU - 3518 (后缀数组)

    Boring counting \[ Time Limit: 1000 ms \quad Memory Limit: 32768 kB \] 题意 给出一个字符串,求出其中出现两次及以上的子串个数,要 ...

  4. HDU4080 Stammering Aliens(二分 + 后缀数组)

    题目 Source http://acm.hdu.edu.cn/showproblem.php?pid=4080 Description Dr. Ellie Arroway has establish ...

  5. 后缀数组 + Hash + 二分 or Hash + 二分 + 双指针 求 LCP ---- 2017icpc 青岛 J Suffix (假题!!)

    题目链接 题目大意: 就是给你n个串每个串取一个后缀,要求把串拼起来要求字典序最小!! sum_length_of_n≤5e5sum\_length\_of\_n\leq 5e5sum_length_ ...

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

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

  7. [Ahoi2013]差异[后缀数组+单调栈]

    链接 解题思路:很明显前面∑1<=i<j<=nlen(Ti)+len(Tj)\sum_{1<=i<j<=n}len(T_i)+len(T_j)∑1<=i< ...

  8. poj2217详解 ( 后缀数组 + 高度数组 )

    题目大概意思就是 给两个字符串,求最长公共字符串子串长度 我们可以考虑用后缀数组和高度数组 一个字符串 中 最长的两个相同字符串长度, 不就是 后缀数组中相邻两个后缀的最长公共前缀, 不就是 高度数组 ...

  9. 树链剖分 + 后缀数组 - E. Misha and LCP on Tree

    E. Misha and LCP on Tree Problem's Link Mean: 给出一棵树,每个结点上有一个字母.每个询问给出两个路径,问这两个路径的串的最长公共前缀. analyse: ...

  10. BZOJ3473:字符串(后缀数组,主席树,二分,ST表)

    Description 给定n个字符串,询问每个字符串有多少子串(不包括空串)是所有n个字符串中至少k个字符串的子串? Input 第一行两个整数n,k. 接下来n行每行一个字符串. Output 一 ...

最新文章

  1. 博途plc连接电脑_西门子CP2431通过SIMATIC NET连接WinCC
  2. python PyQt5.QtWidgets.QWidget类
  3. android调用fragment的方法,AndroidX下使用Activity和Fragment的变化
  4. RTSP客户端接收存储数据(live555库中的openRTSP实例)
  5. Linux+QT界面开发(含数据库)小结
  6. 上项线体表位置_体表定位
  7. python qt5 增加文本框_Python用PyQt5制作弹出式输入框,Qt图形界面编程之QInputDialog...
  8. Lync Server外部访问系列PART4:部署反向代理
  9. WinForm------TreeList修改节点图标和按钮样式
  10. C#通过WebClient/HttpWebRequest实现http的post/get方法
  11. C++ 编码规范建议
  12. 二叉搜索树的后序遍历序列(C++)
  13. matlab鲍威尔算法,鲍威尔法matlab程序
  14. Vue html转word
  15. 利用C++,设置输入某年某月某日,判断这一天是这一年的第几天。
  16. WinCE 编程实验(第一章 引言)
  17. Raspberry Pi 上手准备
  18. H3C路由器清空ARP表
  19. 字符串转换,大写变小写,小写变大写
  20. 全球及中国表面保护胶带行业研究及十四五规划分析报告

热门文章

  1. win10系统如何设置局域网服务器,win10系统设置局域网地址的操作方法
  2. 金仓数据库 KingbaseGIS使用手册(2. 简介)
  3. matlab打反斜杠,[转载]转义字符 反斜杠
  4. 深入剖析RGB、CMYK、HSB、LAB
  5. java 图片下载爬虫_java入门爬虫(爬取网页的图片下载到本地磁盘)
  6. Java丨策略模式丨模拟充值Q币
  7. mysql with,mysql+with
  8. linux 屏幕录像软件,Linux_Linux下好用的5个屏幕录像软件,在很多时候,我们需要将在 Lin - phpStudy...
  9. 全年盘点:2017最酷的10家大数据初创公司
  10. 红帽linux创建c文件,RedHat成功运行的第一个C程序全过程(适合新手)