前言

用了一种很奇怪的方法来解,即二分判断回文,再进行某些奇怪的优化。因为这个方法很奇怪,所以希望如果有问题能够 hack 一下。

题解

我们发现,这题中要求的是字符串 \(SS'SS'\),其中 \(S'\) 是 \(S\) 的反向,那么这个串长度必定为 \(4\) 的倍数。那么我们对于每个位置,寻找一组最大的 \(SS'\),然后找这前面是否有一个与他相同的 \(SS'\),如果有,那么这两组字符串组成一个双倍回文。但是问题在于对于某些情况,例如 bbbbbbbbbbb,在第 \(3\) 和 \(4\) 个字符中间以及第 \(8\) 和 \(9\) 个字符中间,都能取到长度为 \(3\) 的回文 bbb,但是他们共用了第 \(6\) 个字符,从而造成最大双倍回文子串长度为 \(3\) 的假象。为了避免这种假象的发生,同时保证答案长度的最大化,我们需要将共用的部分一分为二,各执一半。

仔细思考,我们可以发现,这一共用的部分只可能是一个字符集大小为 \(1\) 的字符串(语文不好不知道怎么表达)。因为我们知道,回文子串关于对称中心对称,即在该回文子串长度范围内与对称中心距离相同的两个字符相同,两个串共用的部分位于一个串 \(A\) 的末尾和另一个串 \(B\) 的开头,当我们把串 \(B\) 的开头映射到串 \(A\) 的开头(因为 \(A\) 串和 \(B\) 串相同)后,可以发现,只有符合字符集大小为 \(1\) ,才能符合上述性质。

因此,我们预处理时把每一段字符集大小为 \(1\) 的长度等信息做好标记,然后在计算完各位置为中心的最大回文子串长度后减去重复长度即可。

代码

#include<cstdio>
#include<map>
#include<algorithm>
typedef unsigned long long ull;
const int MAXN=500001+5;
std::map<ull,int>map;
char str[MAXN];int tail[MAXN],n,l,rs[MAXN],r,len[MAXN],bll[MAXN],now,cnt,mid;ull cc,hash1[MAXN],hash2[MAXN],pow[MAXN];
ull GetHash1(int l,int r)
{
if(l<1||l>n||r<1||r>n) return ++cc;
return hash1[r]-hash1[l-1]*pow[r-l+1];
}
ull GetHash2(int l,int r)
{
if(l<1||l>n||r<1||r>n) return ++cc;
return hash2[l]-hash2[r+1]*pow[r-l+1];
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%c",&str[i]);
if(!(str[i]>='a'&&str[i]<='z')) i--;
}
for(int i=1;i<=n;i++)
{
if(str[i]!=str[i-1]) {tail[i-1]=1;now++;}
rs[i]=now;
bll[now]++;
}
for(int i=1;i<=n;i++)
hash1[i]=hash1[i-1]*31+str[i]-'a'+1;
for(int i=n;i>=1;i--)
hash2[i]=hash2[i+1]*31+str[i]-'a'+1;
pow[0]=1;
for(int i=1;i<=n;i++)
pow[i]=pow[i-1]*31;
int ans=0,answer,aans=0,last=0;
for(int i=1;i<=n;i++)
{
cnt=0;l=1;r=std::min(i-1,n-i+1);ans=0;answer=0;
while(l<=r)
{
cnt++;
if(cnt>30) break;
mid=(l+r)>>1;
if(GetHash1(i-mid,i-1)!=GetHash2(i,i+mid-1)) {r=mid-1;} else {l=mid+1;ans=std::max(ans,mid);}
}
if(tail[i+ans-1])
ans-=std::min(ans,bll[rs[i+ans-1]])/2;
len[i]=ans;
int result=map[GetHash1(i-ans,i+ans-1)];
if(GetHash1(i-ans,i+ans-1)==GetHash1(i+ans,i+ans*3-1))
{
aans=std::max(aans,ans*4);
} }
printf("%d",aans);
return 0;
}

洛谷 P4287 [SHOI2011]双倍回文题解的更多相关文章

  1. 洛谷P4287 [SHOI2011]双倍回文(回文自动机)

    传送门 听说有大佬用manacher$O(n)$过此题……太强啦…… 说一下PAM的做法吧.(看了题解之后发现)蛮简单的 我们肯定要先建出回文自动机的 然后如果是枚举每一个节点暴跳fail指针肯定得T ...

  2. Manacher || BZOJ 2342: [Shoi2011]双倍回文 || Luogu P4287 [SHOI2011]双倍回文

    题面:[SHOI2011]双倍回文 题解:具体实现时,就是在更新mr时维护前半段是回文串的最长回文串就好了 正确性的话,因为到i时如果i+RL[i]-1<=mr,那么答案肯定在i之前就维护过了: ...

  3. P4287 [SHOI2011]双倍回文(回文树)

    题目描述 记字符串 w 的倒置为 w^R^ .例如 (abcd)^R^=dcba , (abba)^R^=abba . 对字符串x,如果 x 满足 x^R^=x ,则称之为回文:例如abba是一个回文 ...

  4. P4287 [SHOI2011]双倍回文

    题意 考虑对每个节点\(x\)维护\(lastpos_x\)表示\(x\)的所有后缀回文串中第一个\(len\leqslant len_x/2\)并且能和\(x\)最后一个字符匹配的,之后枚举节点,判 ...

  5. [SHOI2011]双倍回文 manacher

    题面: 洛谷:[SHOI2011]双倍回文‘ 题解: 首先有一个性质,本质不同的回文串最多O(n)个. 所以我们可以对于每个i,求出以这个i为结尾的最长回文串,然后以此作为长串,并判断把这个长串从中间 ...

  6. BZOJ2342: [Shoi2011]双倍回文

    2342: [Shoi2011]双倍回文 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 923  Solved: 317[Submit][Status ...

  7. BZOJ 2342: [Shoi2011]双倍回文 马拉车算法/并查集

    2342: [Shoi2011]双倍回文 Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 1123  Solved: 408 题目连接 http://w ...

  8. 2018.06.30 BZOJ 2342: [Shoi2011]双倍回文(manacher)

    2342: [Shoi2011]双倍回文 Time Limit: 10 Sec Memory Limit: 128 MB Description Input 输入分为两行,第一行为一个整数,表示字符串 ...

  9. bzoj 2342: [Shoi2011]双倍回文 -- manacher

    2342: [Shoi2011]双倍回文 Time Limit: 10 Sec  Memory Limit: 128 MB Description Input 输入分为两行,第一行为一个整数,表示字符 ...

随机推荐

  1. 夯实Java基础(二十五)——JDBC使用详解

    1.JDBC介绍 JDBC的全称是Java Data Base Connectivity(Java数据库连接).是一种用于执行SQL语句的Java API,可以为多种关系数据库提供统一访问(例如MyS ...

  2. htmlunit的使用

    原文转自:https://www.cnblogs.com/davidwang456/articles/8693050.html HtmlUnit使用场景 httpClient的局限性 对于使用java ...

  3. C++11常用特性介绍——Lambda表达式

    一.C++11采用配对的方括号[]来创建一个匿名函数并执行,如: #include <iostream> int main() { auto func = []{ std::cout &l ...

  4. base64,base32bit加密解密

    import base64 str='admin' str=str.encode('utf-8') #加密 bs64=base64.b64encode(str) #解密 debs64=base64.b ...

  5. 【协作式原创】自己动手写docker之run代码解析

    linux预备知识 urfave cli预备知识 准备工作 阿里云抢占式实例:centos7.4 每次实例释放后都要重新安装go wget https://dl.google.com/go/go1.1 ...

  6. shell脚本添加脚本执行时间和当前运行次数current running time

    #!/bin/bash ############################ #Author:Bing #Create time:3/31/2017 ####################### ...

  7. 第1节 Scala基础语法:3、环境;4、插件

    1.    Scala编译器安装 1.1.   安装JDK 因为Scala是运行在JVM平台上的,所以安装Scala之前要安装JDK. 1.2.   安装Scala 1.2.1.    Windows ...

  8. tcp连接建立和断开

    TCP协议作为传输层主要协议之一,具有面向连接,端到端,可靠的全双工通信,面向字节流的数据传输协议. 1.TCP报文段 虽然TCP面试字节流,但TCP传输的数据单元却是报文段.TCP报文段分为TCP首 ...

  9. c语言中“#if 0 / #if 1 ... #endif”的作用

    原帖地址:http://www.ourdev.cn/bbs/bbs_content.jsp?bbs_sn=2028608&bbs_page_no=1005&bbs_id=9999 1. ...

  10. C/C++ — CreateThread 相关 API

    使用互斥对象: #include <windows.h> #include <iostream> #define THREADCOUNT 6 HANDLE ghMutex; D ...