BZOJ4755 [JSOI2016]扭动的回文串 【后缀数组】【manacher】
题目分析:
我写了史上最丑的后缀数组,怎么办?
首先manacher一遍两个串,这样只用考虑第三问。用$作为间隔符拼接两个串,把第一个串翻转。枚举回文中心,取最长的回文串,对于剩下的部分利用LCP匹配即可。
代码:
#include<bits/stdc++.h>
using namespace std; #define Sec first.second
#define Fir first.first const int maxn = ; int n,as,f[maxn],sa[maxn],height[maxn],h[maxn],rk[maxn*];
string s1,s2,vk;
int RMQ[maxn][]; void read(){cin >> n; cin >> s1 >> s2;}
int pf[maxn][]; void manacher(string &str){
vk.clear();
memset(f,,sizeof(f));
for(int i=;i<n;i++) vk.push_back(str[i]),vk.push_back('$');
f[] = ; int last = ,ct = ;
for(int i=;i<*n;i++){
f[i] = ;
if(i <= ct+last- && i+f[*ct-i]- <= ct+last-) f[i]=f[*ct-i];
while(i-f[i]>=&&i+f[i]<*n&&vk[i-f[i]]==vk[i+f[i]]){f[i]++;}
if(ct+last- < i+f[i]-) ct = i,last = f[i];
}
}
int X[maxn];
pair<pair<int,int>,int> pr[maxn];
vector <pair<int,int> > vec[maxn];
void get_sa(){
int z = s1.length();
for(int i=;i<z;i++) X[s1[i]]++;
for(int i=;i<=;i++)X[i] += X[i-];
for(int i=;i<z;i++) rk[i] = X[s1[i]];
for(int k=;(<<k)<=z;k++){
for(int i=;i<z;i++)
vec[rk[i+(<<k-)]].push_back(make_pair(rk[i],i));
//pr[i+1]=make_pair(make_pair(rk[i],rk[i+(1<<k-1)]),i);
//sort(pr+1,pr+z+1);
for(int i=,tms=;i<=z;i++)
for(int j=vec[i].size()-;j>=;j--){
pr[++tms]=make_pair(make_pair(vec[i][j].first,i),vec[i][j].second);
vec[i].pop_back();
}
for(int i=z;i>=;i--)
vec[pr[i].Fir].push_back(make_pair(pr[i].Sec,pr[i].second));
for(int i=,tms=;i<=z;i++)
for(int j=vec[i].size()-;j>=;j--){
pr[++tms] = make_pair(make_pair(i,vec[i][j].first),vec[i][j].second);
vec[i].pop_back();
}
int num = ;
for(int i=;i<=z;i++){
if(pr[i].first == pr[i-].first) rk[pr[i].second]=num;
else num++,rk[pr[i].second] = num;
}
}
for(int i=;i<z;i++) sa[rk[i]] = i;
}
void get_height(){
int z = s1.length();
for(int i=;i<z;i++){
if(i) h[i] = max(,h[i-]-); else h[i] = ;
if(rk[i]==) continue;
comp = sa[rk[i]-];
while(s1[comp+h[i]] == s1[i+h[i]])h[i]++;
}
for(int i=;i<z;i++) height[rk[i]] = h[i];
for(int i=;i<=z;i++) RMQ[i][] = height[i];
for(int k=;(<<k)<=z;k++){
for(int i=;i<=z;i++){
if(i+(<<k-)>z) RMQ[i][k] = RMQ[i][k-];
else RMQ[i][k] = min(RMQ[i][k-],RMQ[i+(<<k-)][k-]);
}
}
}
int getLCP(int L,int R){
if(L == R) return n-sa[L]; if(L > R) swap(L,R); L++;
int k = ; while((<<k+)<=R-L+)k++;
return min(RMQ[L][k],RMQ[R-(<<k)+][k]);
} void work(){
manacher(s1);
for(int i=;i<*n;i++) pf[i][] = f[i];
manacher(s2);
for(int i=;i<*n;i++) pf[i][] = f[i];
for(int i=;i<n/;i++) swap(s1[i],s1[s1.length()-i-]);
s1.push_back('$');
for(int i=;i<n;i++) s1.push_back(s2[i]);
get_sa(); get_height();
for(int i=;i<*n;i+=) {
if(pf[i][]%==)pf[i][]--;
int z = (i-pf[i][]+)/,w = (i+pf[i][]-)/;
int L = rk[n-z],R = rk[n+w+];
if(L > R) swap(L,R); int len = getLCP(L,R); as=max(as,w-z++len*);
if(pf[i][]%==)pf[i][]--;
z = (i-pf[i][]+)/,w = (i+pf[i][]-)/;
L = rk[n-z-],R = rk[n+w+];
if(L > R) swap(L,R); len = getLCP(L,R); as = max(as,w-z++len*);
}
for(int i=;i<*n;i+=) {
if(pf[i][]&) pf[i][]--;
int z = i-pf[i][]+,w = i+pf[i][]-;
if(pf[i][] == ){
int L = rk[n-(i-)/-],R = rk[n++(i-)/];
if(L > R) swap(L,R);int len=getLCP(L,R);as=max(as,len*);
} else{
z/=,w/=; int L = rk[n-z],R = rk[n++w];
if(L > R) swap(L,R);int len=getLCP(L,R);as=max(as,w-z++len*);
}
if(pf[i][]&) pf[i][]--;
z = i-pf[i][]+,w = i+pf[i][]-;
if(pf[i][] == ){
int L = rk[n-(i-)/-],R = rk[n++(i-)/];
if(L>R) swap(L,R); int len = getLCP(L,R); as = max(as,len*);
}else{
z/=,w/=; int L = rk[n-z-],R = rk[n+w+];
if(L > R) swap(L,R);int len=getLCP(L,R);as=max(as,w-z++len*); }
}
printf("%d",as);
} int main(){
//freopen("2.in","r",stdin);
read();
work();
return ;
}
BZOJ4755 [JSOI2016]扭动的回文串 【后缀数组】【manacher】的更多相关文章
- [bzoj4755][Jsoi2016]扭动的回文串
来自FallDream的博客,未经允许,请勿转载,谢谢. JYY有两个长度均为N的字符串A和B. 一个“扭动字符串S(i,j,k)由A中的第i个字符到第j个字符组成的子串与B中的第j个字符到第k个字符 ...
- BZOJ4755: [JSOI2016]扭动的回文串——题解
https://www.lydsy.com/JudgeOnline/problem.php?id=4755 JYY有两个长度均为N的字符串A和B. 一个“扭动字符串S(i,j,k)由A中的第i个字符到 ...
- BZOJ4755 JSOI2016扭动的回文串(二分答案+哈希)
显然答案应该是由单串以某位置为中心的极长回文串继续在另一个串里拓展得到的.枚举中间位置二分答案,哈希判断即可.注意考虑清楚怎么处理偶回文,比如像manacher一样加分隔符. #include< ...
- [bzoj3676]回文串[后缀数组+Manacher]
后缀数组+Manacher #include <iostream> #include <cstdio> #include <cstdlib> #include &l ...
- [BZOJ4755][JSOI2016]扭动的回文串(manacher+Hash)
前两种情况显然直接manacher,对于第三种,枚举回文中心,二分回文半径,哈希判断即可. #include<cstdio> #include<algorithm> #defi ...
- 【BZOJ4755】 [Jsoi2016]扭动的回文串
BZOJ4755 [Jsoi2016]扭动的回文串 Solution 考虑对于他给出的 A中的一个回文串: B中的一个回文串: 或者某一个回文的扭动字符串S(i,j,k) 这样子几个限制,我们1,2就 ...
- 【BZOJ4755】扭动的回文串(Manacher,哈希)
[BZOJ4755]扭动的回文串(Manacher,哈希) 题面 BZOJ 题解 不要真的以为看见了回文串就是\(PAM,Manacher\)一类就可以过. 这题显然不行啊. 我们主要考虑如何解决跨串 ...
- [BZOJ]4755: [Jsoi2016]扭动的回文串
Time Limit: 10 Sec Memory Limit: 512 MB Description JYY有两个长度均为N的字符串A和B. 一个"扭动字符串S(i,j,k)由A中的第i ...
- 【题解】Luogu P4324 [JSOI2016]扭动的回文串
原题传送门 这题实际挺水的 先对两个字符串分别跑马拉车 就能求出1.2类扭动回文串最大的长度 考虑第三类的扭动回文串\(S(i,j,k)\),一定可以表示为\(A(i,l)+A(l+1,j)+B(j, ...
随机推荐
- 简单使用redis实现sso单点登录
前面几篇分享了nosql只mongodb,今天简单分享另一个nosql神兵redis. 主要模仿sso单点登录,将登录人信息写入redis.话不多说,直接上马,驾. /// <summary&g ...
- Centos 7 修改系统时区
timedatectl status Local time: 四 2014-12-25 10:52:10 CST Universal time: 四 2014-12-25 02:52:10 UTC R ...
- 七、Json格式的对象都可以通过遍历来获得里面的value值
- Python-爬虫小例子-55
import re from urllib.request import urlopen def getPage(url): response = urlopen(url) return respon ...
- Python-类与对象
类与对象的概念 类即类别.种类,是面向对象设计最重要的概念,从一小节我们得知对象是特征与技能的结合体,而类则是一系列对象相似的特征与技能的结合体. 那么问题来了,先有的一个个具体存在的对象(比如一个具 ...
- Node.js api接口和SQL数据库关联
数据库表创建 服务器环境配置.连接 .操作.数据库 API接口 原则:
- 软件工程(FZU2015) 学生博客列表(最终版)
FZU:福州大学软件工程 张老师的博客:http://www.cnblogs.com/easteast/ 经过前两周选课,最后正式选上课程的所有学生博客如下: 序号 学号后3位 博客 1 629 li ...
- python 中的re模块,正则表达式
一.re模块 re模块中常用的方法. match: 默认从字符串开头开始匹配,re.match('fun', 'funny') 可以匹配出来 'fun' match(pattern, string, ...
- Python之加密模块
hashlib模块 加密方式以md5方式加密举例 是标准模块,直接导入即可 还有其他的加密方式,比如:.sha1()..sha224()..sha256()等,加密后的字符串长度更长,安全性更高 一. ...
- gin框架学习手册
前言 gin框架是go语言的一个框架,框架的github地址是:https://github.com/gin-gonic/gin 转载本文,请标注原文地址:https://www.cnblogs.co ...