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

[SHOI2011]双倍回文 题解

时间:2023-06-10 09:03:05浏览次数:45  
标签:tmp int 题解 枚举 ans 区间 SHOI2011 回文

[SHOI2011]双倍回文 题解

看了一些写回文自动机的大佬的代码,我深感敬畏,于是我转身向Manacher走去

现在荣登最优解第一页……

说实话,这个方法的复杂度是很玄学的,但是加了一些优化之后,就几乎不可能被卡到 \(O(n^2)\) 了。

具体思路如下:

预处理字符串部分就略过吧

  • 我们预先跑一次 Manacher 算法,考虑到我们其实只需要偶数的回文串的信息,所以将步长设为 2 就行了。
int M(0), R(0), p;
for (int i(1); i < n; i += 2) {
    p = R > i ? min(R - i + 1, P[(M<<1) - i]) : 1;
    while (s[i + p] == s[i - p]) ++p; // 向两边扩展 
    if (i + p - 1 > R) M = i, R = i + p - 1; // 更新边界
    P[i] = p;        
}
  • 接着,我们寻找答案。考虑枚举每一个以 i 为中心的偶数回文串。对于这个回文串,我们枚举其回文左区间内的所有点,判断其能否与右区间内对应的区间构成双倍回文即可。换句话来说,假如我们枚举到了 j,那么如果 j 是左侧的合法答案,就一定有 j + P[j] > i

    额,注意一下,这里的 P[i] 指的是回文串的直径,是包括了中间点的元素的。也就是说,回文串所在区间其实是 (i - P[i], i + P[i])(闭区间!)

    但是,这并不是充要条件。我们考虑这样一种情况

    这个时候,j 其实是不合法的,因为绿色的区间才是合法的区间(合法的区间一定是被 i 的回文区间完全包含的!)。所以,对于合法区间的中点,一定在 i 的做右区间中点的左边或者右边。那么实际上,我们只需要枚举 (i, i + P[i]/2] 作为中点即可。

  • 小小的优化:我们需要最大值,所以令答案为 ans,我们枚举 (i + ans, i + P[i]/2] 即可。而且,我们需要的偶数的回文串,所以步长也可以设为 2 来枚举的。

参考代码:

#include <stdio.h>

#define N 1000006

int n, P[N];
char s[N];

inline int min(int x, int y) {
    return x < y ? x : y;
}
inline int max(int x, int y) {
    return x > y ? x : y;
}

int main() {
    scanf("%d", &n);

    char tmp;
    do tmp = getchar(); while (tmp < 'a');
    s[0] = '^', s[1] = '#', s[2] = tmp, s[3] = '#';
    for (int i(2); i <= n; ++i) {
        s[(i<<1)] = getchar(), s[(i<<1)|1] = '#';
    }

    // printf("%s\n", s);

    int ans(0);
    int M(0), R(0), p;
    n = (n<<1) + 2;
    for (int i(1); i < n; i += 2) {
        p = R > i ? min(R - i + 1, P[(M<<1) - i]) : 1;
        while (s[i + p] == s[i - p]) ++p; // 向两边扩展 
        if (i + p - 1 > R) M = i, R = i + p - 1; // 更新边界
        P[i] = p;        
    }
    // 寻找答案
    for (int i(1); i < n; i += 2) {
        int p = P[i] / 2 + 1;
        for (int r(ans); r < p; r += 2) {
            if (P[i + r] > r && P[i - r] > r) ans = r;
        }
    }
    printf("%d\n", ans + ans);
    return 0;
}

标签:tmp,int,题解,枚举,ans,区间,SHOI2011,回文
From: https://www.cnblogs.com/jeefy/p/17470737.html

相关文章

  • P7959 [COCI2014-2015#6] WTF 题解
    P7959[COCI2014-2015#6]WTF题解呃,是一道DP题说实话,原题实际上是不要输出一种方法的……但是似乎放这道题的人想增加一点难度?这里有两种做法,但都是DP。预备观察我们首先观察一些性质,以方便解题。循环不变:我们可以观察到,在\(n\)次变换后,序列会还原。也就是说,两个......
  • 题解 BZOJ4399 魔法少女LJJ
    前言XXX:你瞅你长得那个B样,俺老孙就(氧化钙)......这魔法(J8)少女能不能去死啊啊啊啊啊啊啊啊啊啊......正文"LJJ你是来搞笑的吧"你说得对,但是这数据就是骗人的.首先看题面:然后看样例:最后看数据范围:我惊奇的发现\(c\le7\)!家人们我真难绷qaq...问题分析显......
  • [AGC055B] ABC Supremacy 题解
    [AGC055B]ABCSupremacy题解题目描述给定两个长度为 \(n\) 的字符串 \(a\),\(b\)。你可以进行若干次以下操作:若 \(a\) 中的一个子串为 ABC,BCA 或 CAB,那么可以将这个子串替换为 ABC,BCA 或 CAB。求能否将 \(a\) 变成 \(b\),输出 YES 或 NO。解析不难发现,......
  • chrome 跨域问题解决
    1.后端设置了跨域,https下可以,http不可以高版本chrome配置了策略,如果访问私有网络,会出现禁止跨域chrome://flags/#block-insecure-private-network-requestsBlockinsecureprivatenetworkrequests.......
  • JAVA面试题解惑系列(六)——字符串(String)杂谈
    关键字:java面试题字符串string作者:臧圩人(zangweiren)网址:http://zangweiren.javaeye.com上一次我们已经一起回顾了面试题中常考的到底创建了几个String对象的相关知识,这一次我们以几个常见面试题为引子,来回顾一下String对象相关的其它一些方面。String的l......
  • quickfix协议当有中文时校验位错误问题解决
    quickfix校验位计算都是根据ISO-8859-1编码计算,知道这个规则后续我们处理中文就很好处理了。但是如果用ISO-8859-1编码有中文会出现乱码,如果将CharsetSupport.setCharset设置为UTF-8或者GBK时,在发送数据时会报java.nio.bufferoverflowexception:null,或者校验位失败。1、往step网......
  • JSOI2018 部分题解
    目录潜入行动防御网络列队潜入行动一眼直接DP。设\(f_{i,j,0/1,0/1}\)表示\(i\)子树内放了\(j\)个监听设备,\(i\)是否被子结点覆盖,\(i\)是否放了监听设备,\(i\)子树内除了\(i\)都被覆盖的方案数。转移是一个树形背包,时间复杂度\(\mathcal{O}(nk)\),只是常数有点大。......
  • Competitive Programmer 题解
    题目传送门一道模拟题。纯模拟肯定不行,考虑优化。\(60=2^2\times3\times5\),也就是说我们判断组合后的数字能否被\(2\),\(3\),\(10\)整除即可。如果这个数能被\(2\)整除,那么原数一定会存在偶数;如果这个数能被\(3\)整除,那么它的数字和应该也能被\(3\)整除;如果这个数......
  • 回文数与字符数组
    争取一天一道找实习前刷满500道今天写了一道简单的力扣题,回文数与字符数组Stringres=Integer.toString(x);Stringresrev="";for(inti=0;i<res.length();i++){resrev=res.charAt(i)+resr......
  • CF547E Mike and Friends题解
    题目链接温馨提示:做本题之前可以先尝试这个:洛谷P2414阿狸的打字机(是简单版的uwu)。首先,这个题涉及多模式串匹配,首先想AC自动机。但是有个问题:我们如何去计算一个串出现的次数呢?我们先考虑查询一个串\(a\)在串\(b\)中出现的次数。首先,在AC自动机上有一个性质,就是如果......