首页 > 其他分享 >Luogu P4287 SHOI2011 双倍回文 题解 [ 紫 ] [ manacher ]

Luogu P4287 SHOI2011 双倍回文 题解 [ 紫 ] [ manacher ]

时间:2025-01-03 23:57:21浏览次数:1  
标签:子串 manacher dxx int 题解 && Luogu 回文

双倍回文:回文子串结论的经典应用。

结论

先放本题最关键的结论:一个字符串本质不同的回文子串最多只有 \(n\) 个

考虑如何证明:

假设我们一个一个地在当前字符串(黑色部分)的结尾加入字符(红色部分),那么会出现如下情况:

显然,加入红色字符后,字符串中最多只可能新出现一个本质不同的回文子串。如果这个本质不同的回文子串存在,则这个回文子串就是当前最长的回文子串(深蓝色部分)。

为啥呢,因为假设存在一个更短的回文子串(浅蓝色部分),我们称这个浅蓝色的短回文子串为 \(s\),深蓝色的最长回文子串为 \(t\),则 \(t\) 中一定包含了 \(s\)。而根据回文串的性质,\(s\) 正着读反着读都相同,因此深蓝色的回文串 \(t\) 另一边一定存在另一个 \(s\),且那个 \(s\) 的结尾比当前 \(s\) 的结尾靠前(这两个 \(s\) 在图中用浅蓝色划出来了)。因此它已经被计入本质不同的回文子串中了。

思路

有了这个结论,剩下的就简单了,我们只需要对每个本质不同的回文串判断一下就可以了。

用 manacher 来实现,在每次扩展盒子右端点时统计新拓展部分的回文子串,注意特判细节即可。

因为右端点最多只会拓展 \(n\) 次,所以时间复杂度 \(O(n)\)。

代码

#include <bits/stdc++.h>
#define fi first
#define se second
#define lc (p<<1)
#define rc ((p<<1)|1)
#define eb(x) emplace_back(x)
#define pb(x) push_back(x)
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef long double ldb;
using pi=pair<int,int>;
int m,n,ans=0,d[1000005];
char a[500005],s[1000005];
void init()
{
    n=0;
    s[0]='$';
    s[++n]='#';
    for(int i=1;i<=m;i++)s[++n]=a[i],s[++n]='#';
    s[n+1]='&';
}
void manacher()
{
    d[1]=1;
    for(int i=2,l=0,r=0;i<=n;i++)
    {
        if(i<=r)d[i]=min(r-i+1,d[l+r-i]);
        while(s[i-d[i]]==s[i+d[i]])d[i]++;
        if(i+d[i]-1>r)
        {
            if(s[i]=='#')
            {
                for(int j=r+1;j<=i+d[i]-1;j++)
                {
                    if(s[j]=='#')continue;
                    int dxx=(j-i+1)/2,c=i-dxx;
                    if(d[c]/2>=dxx/2&&s[c]=='#'&&dxx>=1&&dxx*2%4==0)ans=max(ans,dxx*2);
                }            
            }
            l=i-d[i]+1,r=i+d[i]-1;
        }
    }
}
int main()
{
    //freopen("sample.in","r",stdin);
    //freopen("sample.out","w",stdout);
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    cin>>m>>a+1;
    init();
    manacher();
    cout<<ans;
    return 0;
}

标签:子串,manacher,dxx,int,题解,&&,Luogu,回文
From: https://www.cnblogs.com/zhr0102/p/18651247

相关文章

  • P1309 [NOIP2011 普及组] 瑞士轮 题解
    P1309[NOIP2011普及组]瑞士轮题目大意:for(i<=r)让这2n个选手的成绩降序排序,第1-第2打,第3-第4打,......,第2n-1和第2n打i--i+1打,谁能打赢?谁的实力大谁就打赢了排序最快是2nlogn,所以上述暴力过程,时间复杂度是:R(2nlog2n+2n)=2e8超时了解释:为什么是......
  • 题解:AtCoder [ARC176D] Swap Permutation
    题意原题链接给定一个长度为\(n\)的排列\(p\),并执行以下操作\(m\)次:选择\(1\leqi<j\leqn\),交换\(p_i\)和\(p_j\)。定义一个序列\(p\)的权值为\(\sum_{i=1}^{n-1}|p_i-p_{i-1}|\)。求在\(\binom{n}{2}^m\)种可能的操作后,\(p\)的价值之和。答案对\(998244353\)......
  • 题解:CF1830A Copil Copac Draws Trees
    首先这道题肯定不能暴力枚举,我们要思考其他算法。我们可以给每一条边编一个号。然后从根开始遍历这棵树,当一条边的编号比他祖先到他祖先的祖先的那条边的编号还要小时,就说明顺序错了,要再等一轮。这个就简单了,直接dfs就行,注意答案要加\(1\)。#include<bits/stdc++.h>using......
  • 深入理解 Java Set 集合:原理、应用与高频面试题解析
    深入理解JavaSet集合:原理、应用与高频面试题解析在Java中,Set是一种重要的集合接口,用于存储不重复的元素。无论是在实际开发中,还是在面试场景中,Set都是一个高频的知识点。本篇文章将详细介绍JavaSet集合的基础知识、常见实现类、应用场景以及面试常考题,最后通过总结帮助......
  • 题解:CF2044D Harder Problem
    CF2044DHarderProblem思路构造一个\(1\simn\)都出现了一次的数列(这样每个数都是众数了),然后只要保证在数组\(a\)里面出现了的数在最前面就好了。AC代码#include<bits/stdc++.h>usingnamespacestd;#defineN200005longlongt,vis[N],cnt,n,a[N];intmain(){ cin......
  • Solution - Luogu P11456 [USACO24DEC] Interstellar Intervals G
    首先对于这个问题有一个很直观的做法是直接DP。即设\(f_i\)为已经划分出\([1,i]\)部分,且最后一段段尾为\(i\)的方案数。但是这个题还涉及到了有的点可以不染色的情况,所以再设\(g_i\)为已经划分出\([1,i]\)部分,且下一段为\(i+1\)开头的方案数。对于转移\(f\),......
  • 题解 - 出栈序列(2022.10上海月赛丙组T5)
    题目描述给定一个长度为几的、仅由小写字母组成的字符串,将其按序依次放入栈中。请问在所有可能的出栈序列中,字典序最小的出栈序列是多少?输入格式输入第一行,一个正整数几输入第二行,一个长度为几的字符串输出格式输出所有出栈序列中,字典序最小的出栈序列数据范围对......
  • 题解 - 机会成本(2022.9上海月赛丙组T2)
    题目描述明天有门考试,今晚只能复习一门课,请计算应该复习哪一门课,才能让所有考试的分数总和达到最大,如果选择复习第之门课,则这门课的考试分数为a;,若放弃复习第之门课,则这门考试的分数为6;。输入格式第一行:单个整数表示n第二行到第n+1行:每行两个整数表示a;......
  • 【题解】Luogu P7171 [COCI2020-2021#3] Selotejp
    注:题解中\(\operatorname{lsh}\),\(\operatorname{rsh}\),\(\operatorname{or}\)分别表示按位左移、按位右移、按位或,即c++语言中的<<,>>,|。我也是打上轮廓线DP了。设\(f_{x,y,S}\)表示当前在\((x,y)\)格子,前\(m\)个格子的状态为\(S\)时的最小花费。这里的状态是指......
  • USACO2024DEC题解
    P11450[USACO24DEC]FarmerJohn'sCheeseBlockB//FarmerJohn'sCheeseBlockB#include<stdio.h>#include<iostream>usingnamespacestd;intcnt_xy[1005][1005],cnt_yz[1005][1005],cnt_xz[1005][1005];intmain(){intn,q;......