首页 > 其他分享 >[CF30E] Tricky and Clever Password 题解

[CF30E] Tricky and Clever Password 题解

时间:2023-12-29 17:59:12浏览次数:27  
标签:Tricky Clever int 题解 ++ mid len ss ans

[CF30E] Tricky and Clever Password 题解

注意到一个合法字符串首尾相同,考虑用 S 的反转和 S 跑 KMP。

对于只有一个串,暴力 manacher 即可。

匹配到某一位置 \((i, j)\) 时,查询区间最长的奇回文串长度,用二分 + ST 表解决,因为回文串不能超过区间长度。

// Problem: Tricky and Clever Password
// Contest: Luogu
// Author: Moyou
// Copyright (c) 2023 Moyou All rights reserved.
// Date: 2023-12-28 23:22:18

#include <algorithm>
#include <cstring>
#include <iostream>
#include <queue>
// #define int long long
using namespace std;
const int N = 2e5 + 10;

string s, t, ss;
struct qwq {
    int l1, r1, l2, r2, l3, r3, len;
    bool operator < (const qwq &W) {
        return len < W.len;
    }
} ans;

int d[N], st[23][N], pos[23][N], lg[N];
void manacher() {
    string t;
    t = "$";
    for(int i = 0; i < s.size(); i ++)
        t += s[i], t += "#";
    d[1] = 1;
    for(int i = 2, l = 0, r = 0; i < t.size(); i ++) {
        if(i <= r) d[i] = min(d[l + r - i], r - i + 1);
        while(t[i - d[i]] == t[i + d[i]]) d[i] ++;
        if(i + d[i] - 1 > r) r = i + d[i] - 1, l = i - d[i] + 1;
    }
    for(int i = 1; i < t.size(); i += 2) {
        if(d[i] % 2 == 0) d[i] --;
        st[0][i - 1 >> 1] = d[i];
        pos[0][i - 1 >> 1] = (i - 1) / 2;
        if(d[i] > ans.len)
            ans.len = d[i], ans.l1 = (i - d[i] + 1) / 2, ans.r1 = (i + d[i] - 1) / 2 - ans.l1 + 1;
    }
    for(int i = 2; i <= s.size(); i ++) lg[i] = lg[i >> 1] + 1;
    for(int i = 1; i <= lg[s.size()]; i ++)
        for(int j = 0; j + (1 << i) - 1 < s.size(); j ++) {
            if(st[i - 1][j] > st[i - 1][j + (1 << (i - 1))]) st[i][j] = st[i - 1][j], pos[i][j] = pos[i - 1][j];
            else st[i][j] = st[i - 1][j + (1 << i - 1)], pos[i][j] = pos[i - 1][j + (1 << i - 1)];
        }
}
pair<int, int> RMQ(int l, int r) {
    if(l > r) return {-1, -1};
    int k = lg[r - l + 1];
    if(st[k][l] > st[k][r - (1 << k) + 1]) return {st[k][l], pos[k][l]};
    return {st[k][r - (1 << k) + 1], pos[k][r - (1 << k) + 1]};
}
pair<int, int> query(int l, int r) { // 区间最长奇回文串
    int el = 0, er = r - l + 1, ans = 0, anst = 0;
    while(el <= er) {
        int mid = el + er >> 1;
        auto tmp = RMQ(l + (mid - (mid & 1)) / 2, r - (mid - (mid & 1)) / 2);
        if(tmp.first >= mid) el = mid + 1, ans = mid, anst = tmp.second;
        else er = mid - 1;
    }
    return {ans, anst};
}
int ne[N];
signed main() {
    ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
    cin >> s;
    manacher();
    ss = s;
    int n = s.size();
    reverse(ss.begin(), ss.end());
    s = " " + s, ss = " " + ss;
    for(int i = 2, j = 0; i < ss.size(); i ++) {
        while(j && ss[j + 1] != ss[i]) j = ne[j];
        if(ss[j + 1] == ss[i]) j ++;
        ne[i] = j;
    }
    for(int i = 1, j = 0; i < s.size(); i ++) {
        while(j && ss[j + 1] != s[i]) j = ne[j];
        if(ss[j + 1] == s[i]) j ++;
        if(i + j < n) {
            auto t = query(i, n - j - 1);
            if(ans.len < j * 2 + t.first)
                ans = {i - j, j, t.second - (t.first - 1) / 2, t.first, n - j, j, j * 2 + t.first};
        }
    }
    if(ans.l2) {
        cout << 3 << '\n';
        cout << ans.l1 + 1 << ' ' << ans.r1 << '\n' << ans.l2 + 1 << ' ' << ans.r2 << '\n' << ans.l3 + 1 << ' ' << ans.r3 << '\n';
    }
    else {
        cout << 1 << '\n';
        cout << ans.l1 + 1 << ' ' << ans.r1 << '\n';
    }

    return 0;
}

标签:Tricky,Clever,int,题解,++,mid,len,ss,ans
From: https://www.cnblogs.com/MoyouSayuki/p/17935425.html

相关文章

  • P9994 [Ynoi Easy Round 2024] TEST_132 题解
    题解怎么都是用暴力日过去的啊。思路考虑根号分治,设阈值为\(B\)。对于第二维出现次数超过\(B\)的,我们可以在修改时暴力更改,这部分复杂度为\(O(\frac{nm}{B})\)。对于第二维出现次数小于\(B\)的,我们可以在修改是打标记,查询时遍历一遍,这部分的复杂度为\(O(mb)\)。大多数......
  • P9995 [Ynoi2000] rspcn 题解
    思路比较典的ODT题目。发现排序是一个非常有性质的操作。它对区间的更改与颜色段均摊差不多。那么我们可以想到用ODT来维护这一整个序列。具体的,区间排序操作可以用ODT维护每次排序产生的段,每段用线段树维护排序后的结果。每次修改就可以进行线段树的分裂与合并。如......
  • P9991 [Ynoi Easy Round 2023] TEST_107 题解
    思路题目即要求删除区间中的一个或多个颜色。考虑假如枚举删除颜色\(k\)。那么在\(l,r\)中的答案为:\[\max_{i=1}^{m+1}a_i-a_{i-1}\]其中\(a_i\)为颜色\(k\)在\(l\simr\)中的出现位置,\(a_{0}=l,a_{m+1}=r\)。可以分类讨论。答案为\(a_1-l\),那么只需要维护\(......
  • AT_abc020_c 题解
    链接(atcoder)链接(luogu)简单算法组合(?算法一爆搜,时间复杂度\(O(2^{n\timesm}\timest)\),不能通过此题。算法二考虑二分\(t\),然后暴搜,时间复杂度\(O(2^{n\timesm}\timeslog2(t))\),不能通过此题。算法三考虑二分\(t\),然后暴记忆化搜索,时间复杂度\(O(n\timesm......
  • CF1234F 题解
    blog。小清新题,下文\(V=20\)即值域。反转操作,本质就是选两个不相交连续段拼起来。显然合法的最终串长度一定\(\leV\)。将这些合法串预处理出来,那么每个串都对应一个「字母集合」。随便DP一下,求出所有集合中,的最大的合法「字母集合」大小。\(dp_{\smallU}\)就是只选一......
  • CF1917F Construct Tree 题解
    题目链接:https://codeforces.com/contest/1917/problem/F题意有\(n\)条长度\(l_i\)的边,问它们是否能组成一棵\(n+1\)个节点的树,使得树的直径长度为\(d\)。\(n,d\le2000\)。题解首先当然要存在一个边集\(D\),使得\(\sum\limits_{i\inD}l_i=d\),这可以使用背包......
  • 在不使用内置函数和中间变量的情况交换数字LeetCode力扣题解面试题16.01
    #异或法#Kotlin```KotlinclassSolution{  funswapNumbers(numbers:IntArray):IntArray{    numbers[0]=numbers[0]xornumbers[1]    numbers[1]=numbers[1]xornumbers[0]    numbers[0]=numbers[0]xor......
  • AT_joisc2015_h 题解
    传送门题意:给定长为\(n\)的字符串\(s\),你可以选择一个区间,将区间内的字符从小到大排序,求可以得到的最长回文子串长度,字符集大小为\(n\)。很有意思的题目。首先容易做到\(O(n^3)\)。考虑怎么优化。我们先考察排序的区间和回文区间的关系。如果两个区间无交,那么显然排序......
  • CF1835C Twin Clusters 题解
    题目链接点击打开链接题目解法很牛逼的构造题好像随也可以过长度为\(2^{k+1}\)的序列的不同区间有\(2^{2k+1}\)个,值域是\(4^k\),所以一定有解将\(a\)做一遍前缀和,那么问题转化成了找\(s_{r1}\opluss_{l1-1}=s_{r2}\opluss_{l2-1}\)先讲一讲具体做法:按照前\(k\)......
  • ICPC2021Kunming G Glass Bead Game 题解
    QuestionICPC2021KunmingGGlassBeadGame有\(n\)个玻璃珠,\(B_1,B_2,\cdots,B_n\)每一步你可以选择一个\(B_i\)移道第一个位置上,花费的代价为操作前\(B_i\)前面的玻璃珠的个数。已知每一步选择玻璃珠\(B_i\)的概率\(p_i\),问当\(m\rightarrow\infty\)时,在第\(......