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];
ull hsb2[200005];
const int mod1=19260817, mod2=1e9+7;
char sa[200005], sb[200005];
bool iseq(int a, int b, int c, int d){
    if(a>b) return true;
    ull sa1=0, sb1=0;
    if(a)
        sa1 = hsa1[a-1] * bse1[b-a+1] % mod1;
    sa1 = (hsa1[b] - sa1 + mod1) % mod1;
    if(d!=n-1)
        sb1 = hsb1[d+1] * bse1[d-c+1] % mod1;
    sb1 = (hsb1[c] - sb1 + mod1) % mod1;
    if(sa1!=sb1)    return false;
    sa1 = sb1 = 0;
    if(a)
        sa1 = hsa2[a-1] * bse2[b-a+1] % mod2;
    sa1 = (hsa2[b] - sa1 + mod2) % mod2;
    if(d!=n-1)
        sb1 = hsb2[d+1] * bse2[d-c+1] % mod2;
    sb1 = (hsb2[c] - sb1 + mod2) % mod2;
    if(sa1!=sb1)    return false;
    return true;
}
void manacher(char a[], int b[]){
    int id=0, mx=0;
    for(int i=1; i<n; i++){
        if(i<mx)    b[i] = min(b[2*id-i], mx-i);
        else    b[i] = 1;
        while(a[i-b[i]]==a[i+b[i]]) b[i]++;
        if(mx<i+b[i])   mx = i + b[i], id = i;
        ans = max(ans, b[i]);
    }
}
int main(){
    cin>>n;
    scanf("%s", sa);
    scanf("%s", sb);
    for(int i=n; i>=0; i--){
        sa[2*i+1] = ‘#‘;
        sa[2*i+2] = sa[i];
    }
    for(int i=n; i>=0; i--){
        sb[2*i+1] = ‘#‘;
        sb[2*i+2] = sb[i];
    }
    sa[0] = sb[0] = ‘$‘;
    n = 2 * (n + 1);
    bse1[0] = bse2[0] = 1;
    for(int i=1; i<n; i++){
        bse1[i] = bse1[i-1] * 131 % mod1;
        bse2[i] = bse2[i-1] * 131 % mod2;
    }
    ull ff=0;
    for(int i=0; i<n; i++){
        ff = (ff * 131 % mod1 + sa[i]) % mod1;
        hsa1[i] = ff;
    }
    ff = 0;
    for(int i=0; i<n; i++){
        ff = (ff * 131 % mod2 + sa[i]) % mod2;
        hsa2[i] = ff;
    }
    ff = 0;
    for(int i=n-1; i>=0; i--){
        ff = (ff * 131 % mod1 + sb[i]) % mod1;
        hsb1[i] = ff;
    }
    ff = 0;
    for(int i=n-1; i>=0; i--){
        ff = (ff * 131 % mod2 + sb[i]) % mod2;
        hsb2[i] = ff;
    }
    manacher(sa, pa);
    manacher(sb, pb);
    ans--;
    for(int i=1; i<n; i++){
        int pos1=i-pa[i], pos2=i+pa[i]-2;
        int l=0, r=min(pos1, n-pos2), mid, re;
        while(l<=r){
            mid = (l + r) >> 1;
            if(iseq(pos1-mid+1, pos1, pos2, pos2+mid-1))
                re = mid, l = mid + 1;
            else    r = mid - 1;
        }
        ans = max(ans, pa[i]+re-1);
    }
    for(int i=1; i<n; i++){
        int pos1=i-pb[i]+2, pos2=i+pb[i];
        int l=0, r=min(pos1, n-pos2), mid, re;
        while(l<=r){
            mid = (l + r) >> 1;
            if(iseq(pos1-mid+1, pos1, pos2, pos2+mid-1))
                re = mid, l = mid + 1;
            else    r = mid - 1;
        }
        ans = max(ans, pb[i]+re-1);
    }
    cout<<ans<<endl;
    return 0;
}

原文地址:https://www.cnblogs.com/poorpool/p/9049159.html

时间: 2024-10-28 14:22:00

loj2073 「JSOI2016」扭动的回文串的相关文章

【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

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

loj#2076. 「JSOI2016」炸弹攻击 模拟退火

目录 题目链接 题解 代码 题目链接 loj#2076. 「JSOI2016」炸弹攻击 题解 模拟退火 退火时,由于答案比较小,但是温度比较高 所以在算exp时最好把相差的点数乘以一个常数让选取更差的的概率降低 代码 #include<ctime> #include<cmath> #include<cstdio> #include<cstring> #include<algorithm> #define gc getchar() #define

最少回文串--牛客网(秋招备战专场三模)-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都