【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;
int n;
char s[2][N];
uLL sump[2][N],sumq[2][N],pp[N];
int ji[2][N],ou[2][N];
int ansp;

inline uLL hashp(int o,int l,int r){if (l>r || r>n || l<1) return 0;return sump[o][r]-sump[o][l-1]*pp[r-l+1];}
inline uLL hashq(int o,int l,int r){if (l>r || r>n || l<1) return 0;return sumq[o][l]-sumq[o][r+1]*pp[r-l+1];}

int main(){
  pp[0]=1;
  for (ri i=1;i<N;i++) pp[i]=pp[i-1]*p;
  scanf("%d",&n);
  scanf("%s",s[0]+1);
  scanf("%s",s[1]+1);

  for (ri i=1;i<=n;i++)
    for (ri j=0;j<=1;j++) sump[j][i]=sump[j][i-1]*p+s[j][i]-‘A‘;
  for (ri i=n;i>=1;i--)
    for (ri j=0;j<=1;j++) sumq[j][i]=sumq[j][i+1]*p+s[j][i]-‘A‘;

  for (ri i=1;i<=n;i++)
    for (ri j=0;j<=1;j++) {
      int lb=0,rb=min(i-1,n-i);
      while (lb<=rb) {
        int mid=(lb+rb)/2;
        if (hashp(j,i-mid,i-1)==hashq(j,i+1,i+mid)) ji[j][i]=max(ji[j][i],mid),lb=mid+1; else rb=mid-1;
      }
    }
  for (ri i=1;i<=n-1;i++)
    for (ri j=0;j<=1;j++) {
      int lb=0,rb=min(i,n-i);
      while (lb<=rb) {
        int mid=(lb+rb)/2;
        if (hashp(j,i-mid+1,i)==hashq(j,i+1,i+mid)) ou[j][i]=max(ou[j][i],mid),lb=mid+1; else rb=mid-1;
      }
    }
  int ans=0;
  for (ri i=1;i<=n;i++)
    for (ri j=0;j<=1;j++) {
      if (ou[j][i]*2>ans) ans=ou[j][i]*2,ansp=-1;
      if (ji[j][i]*2+1>ans) ans=ji[j][i]*2+1,ansp=-1;
    }

  for (ri i=1;i<=n;i++)
    for (ri j=0;j<=1;j++) {
      if (j==0) {
        int x=i+ji[j][i];
        int lb=ji[j][i]+1,rb=min(i-1,n-i+1);
        while (lb<=rb) {
          int mid=(lb+rb)/2;
          if (hashp(j,i-mid,i-1)==hashq(j,i+1,x)+hashq(j^1,x,i+mid-1)*pp[ji[j][i]]) {
            if (2*mid+1>ans) ans=2*mid+1,ansp=0;
            lb=mid+1;
          }
          else rb=mid-1;
        }
      }
      else {
        int y=i-ji[j][i];
        int lb=ji[j][i]+1,rb=min(i,n-i);
        while (lb<=rb) {
          int mid=(lb+rb)/2;
          if (hashq(j,i+1,i+mid)==hashp(j,y,i-1)+hashp(j^1,i-mid+1,y)*pp[ji[j][i]]) {
            if (2*mid+1>ans) ans=2*mid+1,ansp=1;
            lb=mid+1;
          }
          else rb=mid-1;
        }
      }
    }

  for (ri i=1;i<=n-1;i++)
    for (ri j=0;j<=1;j++) {
      if (j==0) {
        int x=i+ou[j][i];
        int lb=ou[j][i]+1,rb=min(i,n-i+1);
        while (lb<=rb) {
          int mid=(lb+rb)/2;
          if (hashp(j,i-mid+1,i)==hashq(j,i+1,x)+hashq(j^1,x,i+mid-1)*pp[ou[j][i]]) {
            if (2*mid>ans) ans=2*mid,ansp=2;
            lb=mid+1;
          }
          else rb=mid-1;
        }
      }
      else {
        int y=i-ou[j][i]+1;
        int lb=ou[j][i]+1,rb=min(i+1,n-i);
        while (lb<=rb) {
          int mid=(lb+rb)/2;
          if (hashq(j,i+1,i+mid)==hashp(j,y,i)+hashp(j^1,i-mid+2,y)*pp[ou[j][i]]) {
            if (2*mid>ans) ans=2*mid,ansp=3;
            lb=mid+1;
          }
          else rb=mid-1;
        }
      }
    }
  cout<<ans<<endl;
}

原文地址:https://www.cnblogs.com/shxnb666/p/11279734.html

时间: 2024-08-19 22:46:29

【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 第一行

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\)上枚举对称中心,然后感性理解一下发现肯定是取以该对称

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]