3654: 图样图森破

Time Limit: 30 Sec  Memory Limit: 512 MB
Submit: 123  Solved: 66
[Submit][Status][Discuss]

Description

有句老话说得好,人应该要成熟老练,也就是说不能 too simple,也不能 too young。但另外还有这么句老话,人无论何时都应该保持单纯而年轻的心态,换句话说,应该stay simple,stay young。
于是人们就疑惑了,到底应不应该听长者的话呢?不过,不管听还是不听,这与本题都没有任何关系。
长者有一个字符串集合S,此处集合的概念与数学中的集合不同,其中可以含有重复的元素。初始时 S 包含 n 个字符串 s1;s2;:::;sn。有下面两种操作:
• 向S 中加入一个已经存在于 S 中的字符串。
• 从S 中选出两个字符串,将这两个字符串拼接得到的字符串加入集合 S。
长者想要知道,进行任意多次操作之后,在S 中的所有字符串中,最长的回文子串可以有多长?长者毕竟身经百战,他发现长度可以是无穷大,这时你需要输出Infinity。

Input

第一行含有一个整数 n,代表初始时集合的大小。
接下来的n行,每行含有一个字符串。第i行的字符串为si。保证字符串中只含有小写英文字母。

Output

如果最长的回文子串的长度不为无穷大,则输出一个整数,代表其长度;否则输出Infinity。

Sample Input

3
abc
abacde
ecab

Sample Output

7

HINT

第一个样例中,将ecab与abacde拼接,得到ecababacde,其中加粗的部分就是最长的回文子串,长度为 7。可以证明不存在更长的回文子串。第二个样例中,可以将任意多个ha拼接起来,从而得到ha、haha、hahaha等任意奇数长度的回文子串。因此答案为无穷大,输出Infinity。

N<=100

L<=1000

  好恶心……

  这道题貌似打法还挺多的,我就说一下记忆化搜索这种打法好了……

  我们考虑最为“正常”的答案来源,就是几个串拼接在一起,我们尝试从回文串的中心去向外“扩增”回文串,我们可以先枚举每一个串的起始和末尾,因为如果想通过连接形成回文串的话必定会包括回文串的起始或末尾,我们尝试着利用这点和记忆化搜索得到答案。我们设0为从当前点向右的串去找串的右端点进行回文匹配,1为从当前点向左的串找串的左端点进行匹配,由于1和0本质一样,在这里就只说0的情况了。

  我们枚举每一个串的末尾,将它与当前字符及其右进行匹配,这里有一点需要理解,尽管我们找的是串的末尾,但是当前点却不一定是串的起始,它也可能是某个回文串(回文串左端点恰好是一个串的左端点)右侧的第一个不匹配的点,我们找的那个串是为了将那个串拼在回文串的左侧对称的。那么问题来了,怎么找一个正串和一个反串的最大匹配呢?这里就可以用一个骚操作了,我们将所有串连在一起后集体反向,组成一个大串,然后求后缀数组,再RMQ就可以做到O(1)查询两个串的公共子串了。

  最后我们不要忘记算单个串对于答案的贡献,原理还是一样,只不过改为自己和自己匹配以及自己和自己右侧的匹配。

 #include <iostream>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <queue>
#define N 3005
#define M 100005
using namespace std;
int s[M*],st[],en[],rnk[M*],hi[M*],SA[M*],tp[M*];
int cnt[N],f[][M*],mn[M*];
void Rsort(int m,int n)
{
for(int i=;i<=m;i++) cnt[i]=;
for(int i=;i<=n;i++) cnt[rnk[tp[i]]]++;
for(int i=;i<=m;i++) cnt[i]+=cnt[i-];
for(int i=n;i;i--) SA[cnt[rnk[tp[i]]]--]=tp[i];
}
bool cmp(int w,int x,int y)
{
return tp[x]==tp[y]&&tp[x+w]==tp[y+w];
}
void init(int n,int m)
{
for(int i=;i<=n;i++) rnk[i]=s[i],tp[i]=i;
Rsort(m,n);
for(int i,w=,p=;p<n;m=p,w<<=)
{
p=;
for(i=n-w+;i<=n;i++) p++,tp[p]=i;
for(i=;i<=n;i++) if(SA[i]>w) p++,tp[p]=SA[i]-w;
Rsort(m,n);
swap(rnk,tp);
rnk[SA[]]=p=;
for(i=;i<=n;i++) rnk[SA[i]]=cmp(w,SA[i],SA[i-])?p:++p;
}
for(int i=,k=,j;i<=n;hi[rnk[i++]]=k)
for(k=k?k-:k,j=SA[rnk[i]-];s[i+k]==s[j+k];k++);
for(int i=;i<=n;i++) f[][i]=hi[i];
for(int i=;i<=;i++)
{
for(int k=;k<=n&&k+(<<i)-<=n;k++)
{
f[i][k]=(f[i-][k]>f[i-][k+(<<(i-))])?f[i-][k+(<<(i-))]:f[i-][k];
}
}
mn[]=;
for(int i=;i<=n;i++)
{
mn[i]=mn[i-];
if(i==(<<(mn[i]+))) mn[i]++;
}
}
int g[M*][],m,n,bel[M*];
char bb[M];
bool fw[M*][];
void inf_end()
{
printf("Infinity\n");
exit();
}
int get_min(int x,int y)
{
if(x==y) return M;
x=rnk[x],y=rnk[y];
if(x>y) swap(x,y);
x++;
int k=mn[y-x+];
return min(f[k][x],f[k][y-(<<k)+]);
}
int get_lcp(int x,int y)
{
return min(get_min(x,n-y+),min(en[bel[x]]-x+,y-st[bel[y]]+));
}
int dfs(int x,int op)
{
if(fw[x][op]) inf_end();
if(g[x][op]) return g[x][op];
fw[x][op]=;
if(!op)
{
for(int i=;i<=m;i++)
{
int k=get_lcp(x,en[i]);
int xx,yy;
xx=x+k-,yy=en[i]-k+;
if(xx!=en[bel[x]]&&yy!=st[i]) g[x][op]=max(g[x][op],k*);
else if(xx==en[bel[x]]&&yy==st[i]) inf_end();
else if(xx==en[bel[x]]) g[x][op]=max(g[x][op],k*+dfs(yy-,));
else g[x][op]=max(g[x][op],k*+dfs(xx+,));
}
}
else
{
for(int i=;i<=m;i++)
{
int k=get_lcp(st[i],x);
int xx,yy;
xx=x-k+,yy=st[i]+k-;
if(xx!=st[bel[x]]&&yy!=en[i]) g[x][op]=max(g[x][op],k*);
else if(xx==st[bel[x]]&&yy==en[i]) inf_end();
else if(xx==st[bel[x]]) g[x][op]=max(g[x][op],k*+dfs(yy+,));
else g[x][op]=max(g[x][op],k*+dfs(xx-,));
}
}
fw[x][op]=;
return g[x][op];
}
int ans;
int main()
{
scanf("%d",&m);
for(int i=;i<=m;i++)
{
scanf("%s",bb+);
int len=strlen(bb+);
st[i]=n+;
for(int j=;j<=len;j++)
{
n++;
s[n]=bb[j]-'a'+;
bel[n]=i;
}
en[i]=n;
}
for(int i=n+,j=n;i<=n*;i++,j--) s[i]=s[j];
n<<=;
init(n,);
for(int i=;i<=m;i++)
{
ans=max(ans,dfs(st[i],));
ans=max(ans,dfs(en[i],));
}
for(int i=;i<=m;i++)
{
for(int j=st[i];j<=en[i];j++)
{
int k=get_lcp(j,j);
int xx=j+k-,yy=j-k+;
if(xx!=en[i]&&yy!=st[i]) ans=max(ans,k*-);
else if(xx==en[i]&&yy==st[i]) inf_end();
else if(xx==en[i])ans=max(ans,k*-+dfs(yy-,));
else ans=max(ans,k*-+dfs(xx+,));
}
for(int j=st[i];j<en[i];j++)
{
int k=get_lcp(j+,j);
int xx=j-k+,yy=j++k-;
if(xx!=st[i]&&yy!=en[i]) ans=max(ans,k*);
else if(xx==st[i]&&yy==en[i]) inf_end();
else if(xx==st[i])ans=max(ans,k*+dfs(yy+,));
else ans=max(ans,k*+dfs(xx-,));
}
}
printf("%d\n",ans);
return ;
}

Bzoj 3654 图样图森波 题解的更多相关文章

  1. P3900 [湖南集训]图样图森破

    P3900 [湖南集训]图样图森破 链接 分析: 感觉像个暴力. 可以枚举回文串的回文中心,即枚举一个串,枚举一个串的位置作为回文中心,然后求出这个串内的回文串的长度. 此时如果回文串两端都没有到这个 ...

  2. Kruskal算法及其类似原理的应用——【BZOJ 3654】tree&&【BZOJ 3624】[Apio2008]免费道路

    首先让我们来介绍Krukal算法,他是一种用来求解最小生成树问题的算法,首先把边按边权排序,然后贪心得从最小开始往大里取,只要那个边的两端点暂时还没有在一个联通块里,我们就把他相连,只要这个图里存在最 ...

  3. BZOJ 4033: [HAOI2015]树上染色题解

    BZOJ 4033: [HAOI2015]树上染色题解(树形dp) 标签:题解 阅读体验:https://zybuluo.com/Junlier/note/1327400 原题地址: BZOJ 403 ...

  4. 更新一波题解(最近做的三个dp题)

    很久没写题解了,去ec之前来填一填坑,希望能攒攒人品... 首先是去年上海F题..uvalive7143 题意: 给n个人分 m间房子,每个房间的容量是已知的,其中有k对双胞胎,双胞胎可以看作相同的人 ...

  5. [BZOJ 1032][JSOI 2007]祖玛 题解(区间DP)

    [BZOJ 1032][JSOI 2007]祖玛 Description https://www.lydsy.com/JudgeOnline/problem.php?id=1032 Solution ...

  6. [BZOJ 2299][HAOI 2011]向量 题解(裴蜀定理)

    [BZOJ 2299][HAOI 2011]向量 Description 给你一对数a,b,你可以任意使用(a,b), (a,-b), (-a,b), (-a,-b), (b,a), (b,-a), ...

  7. bzoj 3528 [ZJOI2014] 星系调查 题解

    [原题] 星系调查 [问题描写叙述] 银河历59451年.在银河系有许很多多已被人类殖民的星系.如果想要在行 星系间往来,大家一般使用连接两个行星系的跳跃星门.  一个跳跃星门能够把 物质在它所连接的 ...

  8. bzoj 1860: [Zjoi2006]Mahjong麻将 题解

    [原题] 1860: [Zjoi2006]Mahjong麻将 Time Limit: 1 Sec  Memory Limit: 64 MB Submit: 211  Solved: 122 [Subm ...

  9. BZOJ 2179 FFT快速傅立叶 题解

    bzoj 2179 Description 给出两个n位10进制整数x和y,你需要计算x*y. [题目分析] 高精裸题.练手. [代码] 1.手动高精 #include<cstdio> # ...

随机推荐

  1. Win10 UWP版《芒果TV》v2.4.0直播超女,芒果台综艺一网打尽

    Win10 UWP版<芒果TV>直播超女,芒果台综艺一网打尽 Win10版UWP<芒果TV>自2015年9月登录商店以来,一直在持续更新,积极改进,拥有芒果台视频的独家点播和直 ...

  2. ARTS 12.31 - 1.4

    Algorithm 这是一道需要用动态规划的问题.求字符串的最长回文子序列. 复习了一遍动态规划,重点是要分析出最优解所包含的子问题的最优解,把过程描述为数学公式. 题目https://leetcod ...

  3. QT5.8 VS2017 编译教程(可以使用VS2017 XP兼容包)

    1.下载QT5.8源码 这个我不做过多解释. 2.安装使用的环境 visual studio 2017  Python Perl  Ruby 安装好,并配置好环境PATH变量. 3.修改错误代码 错误 ...

  4. 开源libco库:单机千万连接、支撑微信8亿用户的后台框架基石

    微信于2013年开源的ibco库,是微信后台大规模使用的c/c++协程库,2013年至今稳定运行在微信后台的数万台机器上.libco在2013年的时候作为腾讯六大开源项目首次开源,ibco支持后台敏捷 ...

  5. mysql8解压版安装

    1.下载 下载mysql8 2.安装 ① 解压到需要安装的目录,然后新建一个my.ini(位于解压目录下,与bin目录在同一个目录下) # For advice on how to change se ...

  6. 从IntToHex()说起,栈/堆地址标准写法 good

    学习中的一些牢骚.栈/堆地址标准写法. 2017-02-12 • 杂谈 • 暂无评论 • 老衲 •浏览 226 次 我一直都在寻找各种业务功能的最简单写法,用减法的模式来开发软件.下面是我的写法,如果 ...

  7. 各种 MacBook 和 5K iMac 屏幕分辨率对比

    苹果全新 12寸超薄 MacBook 比曾经最薄的 MacBook Air 更薄,不过却配备了Retina 显示屏.12寸 Retina MacBook 上的显示屏分辨率为2304*1440,虽然不如 ...

  8. PHP PSR4自动加载代码赏析

    第一部分是引入自动加载配置文件 1.入口文件:autoload.php里面没什么东西,就是导入ComposerAutoloader主题文件,一般由一个复杂的名字,不过不用担心就是机器随机生成的一个码而 ...

  9. [2017.02.23] Java8 函数式编程

    以前学过Haskell,前几天又复习了其中的部分内容. 函数式编程与命令式编程有着不一样的地方,函数式编程中函数是第一等公民,通过使用少量的几个数据结构如list.map.set,以及在这些数据结构上 ...

  10. wed前端html/css简单理解

    开发工具: txt文本 / dreamwave:DW(cs6/cc) / Hbuilder / webstorm / sublime / vscode 前端: 知识架构: 3层: 结构 / 表现 / ...