P4324 [JSOI2016]扭动的回文串

传送门

对\(A\)、\(B\)串各跑一遍\(manacher\),求出第\(1\)、\(2\)类扭动回文串的最大长度。

考虑第三类的扭动回文串\(S(i,j,k)\),一定可以表示为\(A(i,l)+A(l+1,j)+B(j,k)\)或\(A(i,j)+B(j,l)+B(l+1,k)\),其中,第一段与第三段对称(第一段正着\(Hash\)和第三段反着\(Hash\)相同),第二段是一个回文子串,三段都可以是空串。

我们可以分别在\(AB\)上枚举对称中心,然后感性理解一下发现肯定是取以该对称中心为中心的最长回文串作为中间那段是最优的。然后对于第一段和第三段分别二分其长度就好了

//minamoto
#include<bits/stdc++.h>
#define R register
#define fp(i,a,b) for(R int i=a,I=b+1;i<I;++i)
#define fd(i,a,b) for(R int i=a,I=b-1;i>I;--i)
#define go(u) for(int i=head[u],v=e[i].v;i;i=e[i].nx,v=e[i].v)
template<class T>inline bool cmax(T&a,const T&b){return a<b?a=b,1:0;}
template<class T>inline bool cmin(T&a,const T&b){return a>b?a=b,1:0;}
using namespace std;
char buf[1<<21],*p1=buf,*p2=buf;
inline char getc(){return p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++;}
inline char gc(){char ch;while((ch=getc())<'A'||ch>'Z');return ch;}
const int N=2e5+5,P1=1e9+7,P2=998244353;
int a[N],b[N],sum[N][2],num[N][2],bin[N][2],f[N],g[N];
int n,m,ans,p,l,r;char ch;
bool ck(int l1,int r1,int l2,int r2){
    int x,y;
    x=(sum[r1][0]-1ll*sum[l1-1][0]*bin[r1-l1+1][0]%P1)%P1;
    y=(num[l2][0]-1ll*num[r2+1][0]*bin[r2-l2+1][0]%P1)%P1;
    x=(x+P1)%P1,y=(y+P1)%P1;if(x!=y)return false;
    x=(sum[r1][1]-1ll*sum[l1-1][1]*bin[r1-l1+1][1]%P2)%P2;
    y=(num[l2][1]-1ll*num[r2+1][1]*bin[r2-l2+1][1]%P2)%P2;
    x=(x+P2)%P2,y=(y+P2)%P2;return x==y;
}
int calc(int j,int k){
    int l=0,r=min(j,n-k+1),res=0;
    while(l<=r){
        int mid=(l+r)>>1;
        if(ck(j-mid+1,j,k,k+mid-1))res=mid,l=mid+1;else r=mid-1;
    }return res;
}
int main(){
//  freopen("testdata.in","r",stdin);
    scanf("%d",&n);bin[0][0]=bin[0][1]=1;fp(i,1,n)bin[i][0]=1ll*bin[i-1][0]*27%P1,bin[i][1]=1ll*bin[i-1][1]*27%P2;
    a[0]=b[0]=0,a[n*2+2]=b[n*2+2]=28,a[1]=b[1]=27;
    fp(i,1,n)ch=gc(),a[i*2]=ch-'A'+1,a[i*2+1]=27;
    fp(i,1,n)ch=gc(),b[i*2]=ch-'A'+1,b[i*2+1]=27;
    p=0;fp(i,2,n*2){
        if(i<=p+f[p])f[i]=min(f[2*p-i],p+f[p]-i);
        while(a[i-f[i]-1]==a[i+f[i]+1])++f[i];
        if(i+f[i]>p+f[p])p=i;
    }p=0;fp(i,2,n*2){
        if(i<=p+g[p])g[i]=min(g[2*p-i],p+g[p]-i);
        while(b[i-g[i]-1]==b[i+g[i]+1])++g[i];
        if(i+g[i]>p+g[p])p=i;
    }fp(i,2,n*2)cmax(ans,max(f[i],g[i]));
    fp(i,1,n){
        sum[i][0]=(1ll*sum[i-1][0]*27%P1+a[i*2])%P1;
        sum[i][1]=(1ll*sum[i-1][1]*27%P2+a[i*2])%P2;
    }fd(i,n,1){
        num[i][0]=(1ll*num[i+1][0]*27%P1+b[i*2])%P1;
        num[i][1]=(1ll*num[i+1][1]*27%P2+b[i*2])%P2;
    }fp(i,2,n*2){
        l=(i-f[i]+1)>>1,r=(i+f[i])>>1;
        cmax(ans,f[i]+calc(l-1,r)*2);
        l=(i-g[i]+1)>>1,r=(i+g[i])>>1;
        cmax(ans,g[i]+calc(l,r+1)*2);
    }printf("%d\n",ans);return 0;
}

原文地址:https://www.cnblogs.com/bztMinamoto/p/10107707.html

时间: 2024-07-30 19:32:56

P4324 [JSOI2016]扭动的回文串的相关文章

[BZOJ]4755: [Jsoi2016]扭动的回文串

Time Limit: 10 Sec  Memory Limit: 512 MB Description JYY有两个长度均为N的字符串A和B. 一个"扭动字符串S(i,j,k)由A中的第i个字符到第j个字符组成的子串与B中的第j个字符到第k个字符组成的子串拼接而成. 比如,若A='XYZ',B='UVW',则扭动字符串S(1,2,3)='XYVW'. JYY定义一个"扭动的回文串"为如下情况中的一个: 1.A中的一个回文串: 2.B中的一个回文串: 3.或者某一个回文的扭动

[Jsoi2016]扭动的回文串

Description JYY有两个长度均为N的字符串A和B. 一个"扭动字符串S(i,j,k)由A中的第i个字符到第j个字符组成的子串 与B中的第j个字符到第k个字符组成的子串拼接而成. 比如,若A='XYZ',B='UVW',则扭动字符串S(1,2,3)='XYVW'. JYY定义一个"扭动的回文串"为如下情况中的一个: 1.A中的一个回文串: 2.B中的一个回文串: 3.或者某一个回文的扭动字符串S(i,j,k) 现在JYY希望找出最长的扭动回文串. Input 第一行

【JSOI2016】扭动的回文串

题面 https://www.luogu.org/problem/P4324 题解 #include<cstdio> #include<iostream> #include<cstring> #include<algorithm> #define N 100050 #define uLL unsigned long long #define ri register int using namespace std; const uLL p=1233107; i

loj2073 「JSOI2016」扭动的回文串

ref 主要是要理解"撑到"最长这个概念 (为啥我的代码这么长QAQ #include <iostream> #include <cstdio> using namespace std; typedef unsigned long long ull; int n, pa[200005], pb[200005], ans; ull bse1[200005], bse2[200005], hsa1[200005], hsa2[200005], hsb1[200005

最少回文串--牛客网(秋招备战专场三模)-C++方向

题目描述:一个字符串从左向右和从右向左读都完全一样则是回文串,给定一个字符串,问该字符串中的字符所能组成的最少的回文串的个数为多少 解题思路:如果一个字符出现的次数为偶数,则必能组成回文串,如果一个字符出现奇数次,只能自己组成回文串,题目中问最少的回文串数目,即求出现次数为奇数次的字符个数即可,定义a存储每个字符出现的次数,统计出现奇数次的字符的个数,即为输出 1 #include <iostream> 2 #include <string> 3 using namespace s

回文串问题

1.回文串的判断 #include <iostream> #include <string.h> using namespace std; //回文串的判断 bool isPalindrome(const char* src) { if(src == NULL) return true; int end = strlen(src)-1,begin = 0; while(begin < end)//从两边向中间判断,当然也可以从中间向两边判断 { if(src[begin] !

bzoj 2565: 最长双回文串

Description 顺序和逆序读起来完全一样的串叫做回文串.比如acbca是回文串,而abc不是(abc的顺序为"abc",逆序为"cba",不相同).输入长度为n的串S,求S的最长双回文子串T,即可将T分为两部分X,Y,(|X|,|Y|≥1)且X和Y都是回文串. Input 一行由小写英文字母组成的字符串S. Output 一行一个整数,表示最长双回文子串的长度. Sample Input baacaabbacabb Sample Output 12 HINT

BZOJ2565:最长双回文串

2565: 最长双回文串 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 2195  Solved: 1119[Submit][Status][Discuss] Description 顺序和逆序读起来完全一样的串叫做回文串.比如acbca是回文串,而abc不是(abc的顺序为"abc",逆序为"cba",不相同). 输入长度为n的串S,求S的最长双回文子串T,即可将T分为两部分X,Y,(|X|,|Y|≥1)且X和Y都

Power oj/2610[判断回文串]

题目链接[https://www.oj.swust.edu.cn/problem/show/2610] 题意:给你一个字符串,让你判断这个字符串是不是回文串,字符串的长度是1<len<1e7,内存是4096KB. 题解:首先这1e7个字符是存不下的,1e71024=9765KB>4096kB.那么怎么办?字符串哈希,先对字符串的前半部分进行哈希,然后在对字符串后半部分进行哈希,如果两部分的哈希值相同,那么这个字符串就是回文串. BKDRH哈希,哈希公式为has=has*seed+s[i]