Problem:

洛谷3546

Analysis:

I gave up and saw other's solution when I had nearly thought of the method ... What a pity

Let's define a border of string \(s\) as a prefix \(p\) of \(s\) that \(p\) is also a suffix of \(s\), and \(p\) is not longer than half of \(s\). What the problem asked us to look for is a number \(L\), that the prefix of length \(L\) can be divided into two string \(s1\) and \(s2\) , and the suffix of length \(L\) can be divided into two string \(s2\) and \(s1\), so that this pair of prefix and suffix is cyclically equivalent. Obviously, \(s1\) is a border of string \(s\). Another fact is, if \(s1\) is of length \(len\), \(s2\) is a border of the substring \([len, n - len - 1]\). Define \(f[len]\) as the length of the maximum border of the substring \([len, n - len - 1]\) . Let's enumerate the length of \(s1\) as \(len\) brutely, and for all legal \(len\) ("legal" means the prefix of length \(len\) is a border of \(s\). We can check it by hashing in \(O(1)\) time), the answer is \(len + f[len]\).

Now the problem is how to calculate \(f[len]\). Brute force takes \(O(n^2)\) complexity, but the useful fact below can decrease the complexity to \(O(n)\) :

\[f[i]\leq f[i+1]+2
\]

To make it easy, look at the (beautiful) picture below.

The first picture shows the situation when \(f[i]=f[i+1]+2\), and the second picture shows if \(f[i]\) (the black ones) is more than \(f[i+1]\) (the red ones) plus \(2\) , the \(f[i+1]\) must be wrong, for there's a longer border (the blue ones) of substring \([i+1, n-i-2]\).

Because of this fact, we can solve \(f[len]\) in \(O(n)\) time. We initialize \(f[i]\) as \(f[i+1]+2\), and decrease it until the substring \([i, n-i-1]\) has a border of length \(f[i]\). The proof of the complexity is similar to the one of solving \(height\) array by Suffix Array.

Code:

#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cctype>
using namespace std; namespace zyt
{
template<typename T>
inline bool read(T &x)
{
char c;
bool f = false;
x = 0;
do
c = getchar();
while (c != EOF && c != '-' && !isdigit(c));
if (c == EOF)
return false;
if (c == '-')
f = true, c = getchar();
do
x = x * 10 + c - '0', c = getchar();
while (isdigit(c));
if (f)
x = -x;
return true;
}
inline bool read(char *const s)
{
return ~scanf("%s", s);
}
template<typename T>
inline void write(T x)
{
static char buf[20];
char *pos = buf;
if (x < 0)
putchar('-'), x = -x;
do
*pos++ = x % 10 + '0';
while (x /= 10);
while (pos > buf)
putchar(*--pos);
}
const int N = 1e6 + 10;
int f[N], n;
// f[i] is the maximum length of the border of substr[i, n - i - 1]
char str[N];
namespace Hash
{
typedef long long ll;
typedef pair<int, int> pii;
typedef pii hash_t;
hash_t h[N], pow[N];
const hash_t seed = hash_t(61, 67), p = hash_t(1e9 + 7, 1e9 + 9);
hash_t operator + (const hash_t &a, const hash_t &b)
{
return hash_t((a.first + b.first) % p.first, (a.second + b.second) % p.second);
}
hash_t operator - (const hash_t &a, const hash_t &b)
{
return hash_t((a.first - b.first + p.first) % p.first,
(a.second - b.second + p.second) % p.second);
}
hash_t operator * (const hash_t &a, const hash_t &b)
{
return hash_t(int((ll)a.first * b.first % p.first),
int((ll)a.second * b.second % p.second));
}
void init()
{
pow[0] = make_pair(1, 1);
for (int i = 1; i < N; i++)
pow[i] = pow[i - 1] * seed;
}
inline int ctoi(const char c)
{
return c - 'a';
}
void get(const char *const s)
{
h[0] = make_pair(ctoi(s[0]), ctoi(s[0]));
for (int i = 1; i < n; i++)
h[i] = h[i - 1] * seed + make_pair(ctoi(s[i]), ctoi(s[i]));
}
hash_t extract(const int l, const int r)
{
return l ? (h[r] - h[l - 1] * pow[r - l + 1]) : h[r];
}
}
using namespace Hash;
void mk_f()
{
f[n >> 1] = 0;
for (int i = (n >> 1) - 1; i >= 0; i--)
{
f[i] = min(f[i + 1] + 2, (n >> 1) - i);
while (f[i] && extract(i, i + f[i] - 1) != extract(n - i - f[i], n - i - 1))
--f[i];
}
}
int work()
{
read(n), read(str);
init();
get(str);
mk_f();
int ans = 0;
for (int i = 1; i <= (n >> 1); i++)
if (extract(0, i - 1) == extract(n - i, n - 1))
ans = max(ans, i + f[i]);
write(ans);
return 0;
}
}
int main()
{
return zyt::work();
}

【洛谷3546_BZOJ2803】[POI2012]PRE-Prefixuffix(String Hash)的更多相关文章

  1. 洛谷P3538 [POI2012]OKR-A Horrible Poem [字符串hash]

    题目传送门 A Horrible Poem 题目描述 Bytie boy has to learn a fragment of a certain poem by heart. The poem, f ...

  2. 洛谷P3237 米特运输 [HNOI2014] hash/二进制分解

    正解:hash/二进制分解 解题报告: 传送门! umm首先提取下题意趴QAQ 大概是说给一棵树,每个点有一个权值,要求修改一些点的权值,使得同一个父亲的儿子权值相同,且父亲的权值必须是所有儿子权值之 ...

  3. 洛谷P1117 优秀的拆分【Hash】【字符串】【二分】【好难不会】

    题目描述 如果一个字符串可以被拆分为AABBAABB的形式,其中 A和 B是任意非空字符串,则我们称该字符串的这种拆分是优秀的. 例如,对于字符串aabaabaaaabaabaa,如果令 A=aabA ...

  4. 洛谷 P3539 [POI2012]ROZ-Fibonacci Representation 解题报告

    P3539 [POI2012]ROZ-Fibonacci Representation 题意:给一个数,问最少可以用几个斐波那契数加加减减凑出来 多组数据10 数据范围1e17 第一次瞬间yy出做法, ...

  5. 洛谷P3533 [POI2012]RAN-Rendezvous

    P3533 [POI2012]RAN-Rendezvous 题目描述 Byteasar is a ranger who works in the Arrow Cave - a famous rende ...

  6. 洛谷P3531 [POI2012]LIT-Letters

    题目描述 Little Johnny has a very long surname. Yet he is not the only such person in his milieu. As it ...

  7. BZOJ2801/洛谷P3544 [POI2012]BEZ-Minimalist Security(题目性质发掘+图的遍历+解不等式组)

    题面戳这 化下题面给的式子: \(z_u+z_v=p_u+p_v-b_{u,v}\) 发现\(p_u+p_v-b_{u,v}\)是确定的,所以只要确定了一个点\(i\)的权值\(x_i\),和它在同一 ...

  8. 洛谷P3539 [POI2012] ROZ-Fibonacci Representation

    题目传送门 转载自:five20,转载请注明出处 本来看到这题,蒟蒻是真心没有把握的,还是five20大佬巨orz 首先由于斐波拉契数的前两项是1,1 ,所以易得对于任何整数必能写成多个斐波拉契数加减 ...

  9. 洛谷P3537 [POI2012]SZA-Cloakroom(背包)

    传送门 蠢了……还以为背包只能用来维护方案数呢……没想到背包这么神奇…… 我们用$dp[i]$表示当$c$的和为$i$时,所有的方案中使得最小的$b$最大时最小的$b$是多少 然后把所有的点按照$a$ ...

随机推荐

  1. Flask蓝图基本使用

    Flask蓝图基本使用 Flask通过使用蓝图将视图函数模块化,使应用显得更加规整 比如我们的应用的视图函数包括用户相关和文章相关,那么我们可以通过建立两个py文件分别存储两类视图函数 user.py ...

  2. 第十二节:Web爬虫之MongoDB数据库安装与数据存储

    MongoDB是一个基于分布式文件存储的数据库.由C++语言编写.旨在为WEB应用提供可扩展的高性能数据存储解决方案. MongoDB是一个介于关系数据库和非关系数据库之间的产品,是非关系数据库当中功 ...

  3. BNUOJ 13358 Binary Apple Tree

    Binary Apple Tree Time Limit: 1000ms Memory Limit: 16384KB This problem will be judged on Ural. Orig ...

  4. Poor Hanamichi

    Poor Hanamichi Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)To ...

  5. [luoguP1282] 多米诺骨牌(DP + 背包)

    传送门 将问题转换成分组背包,每一组有上下两个,每一组中必须选则一个,上面的价值为0,下面的价值为1,求价值最小 因为要求上下两部分差值最小,只需从背包大小为总数 / 2 时往前枚举,找最小答案即可. ...

  6. NEU 1351 Goagain and xiaodao's romantic story I

    题目描述 Do you know goagain? If the answer is “no”, well, you can leave NEUACM. Goagain is the most per ...

  7. Python - 对多继承以及super的一些了解

    Python支持多继承,与C++一样都会出现一种问题:子类继承的多个父类又继承了同一个父类,这时就有可能会出现父类构造方法被调用多次的情况.关于这个问题,我找了一些资料,虽然没有亲自全部验证,这里我总 ...

  8. select节点clone全解析

    select节点clone全解析 2009-12-18 在开发ns-log项目中,统计分类有复制的功能.由于之前的统计分类中的数据是通过JS赋值进去的,之后用户可能又进行了修改,发现进行节点克隆时,出 ...

  9. @ResponseBody 返回json字符串的核心类是org.springframework.http.converter.json.MappingJacksonHttpMessageConverter,它使用了Jackson 这个开源的第三方类库。主要是以下两个jar包:jackson-core-asl-1.6.4.jar;jackson-mapper-asl-1.6.4.jar

    @ResponseBody 返回json字符串的核心类是org.springframework.http.converter.json.MappingJacksonHttpMessageConvert ...

  10. 导入数据到mysql的一种简单的方法

    由于ubuntu默认自带的mysql版本号为5.5,并不能使用load data infile这样的高级的功能,因此我们写了一个通用的脚本来上传文件 shell脚本 cat ./employee.cs ...