首页 > 其他分享 >abc284F 前缀+逆序+后缀

abc284F 前缀+逆序+后缀

时间:2024-03-08 12:22:24浏览次数:28  
标签:P2 P3 后缀 int M1 M3 M2 abc284F 逆序

题面:给一个长度为2n的字符串T,问是否存在长度为n的字符串S,满足:T = S的前缀 + 整串S逆序 + S的后缀。
范围:n<=1e6

思路:字符串哈希,枚举S的起点逐一判断,如果前i个字符加后n-i个字符组成的长为n的字符串,正好和中间串的逆序相同,则为解。

#include <bits/stdc++.h>
using namespace std;
#define int long long
#define rep(i,a,b) for(int i=a; i<=b; i++)
#define per(i,a,b) for(int i=b; i>=a; i--)

using hval = tuple<int,int,int>;
struct Hasher {
    const int B1 = 131, M1 = 1000000123;
    const int B2 = 137, M2 = 1000000223;
    const int B3 = 139, M3 = 1000000007;
    vector<int> P1, P2, P3, L1, L2, L3;
    template<typename InputIt>
    void init(InputIt st, InputIt ed) {
        int n = distance(st, ed);
        P1 = P2 = P3 = vector<int>(n+5, 1);
        rep(i,1,n) {
            P1[i] = P1[i-1] * B1 % M1;
            P2[i] = P2[i-1] * B2 % M2;
            P3[i] = P3[i-1] * B3 % M3;
        }
        L1 = L2 = L3 = vector<int>(n+5, 0);
        rep(i,1,n) {
            L1[i] = (L1[i-1] * B1 + st[i-1]) % M1;
            L2[i] = (L2[i-1] * B2 + st[i-1]) % M2;
            L3[i] = (L3[i-1] * B3 + st[i-1]) % M3;
        }
    }
    hval get(initializer_list<int> arg) { // [l1,r1),[l2,r2)..., 0-based
        assert(arg.size() % 2 == 0);
        int x = 0, y = 0, z = 0;
        auto it = arg.begin();
        while (it != arg.end()) {
            int l = *it++, r = *it++;
            x = x * P1[r-l] % M1; x += (L1[r] - L1[l] * P1[r-l]) % M1; if (x < 0) x += M1;
            y = y * P2[r-l] % M2; y += (L2[r] - L2[l] * P2[r-l]) % M2; if (y < 0) y += M2;
            z = z * P3[r-l] % M3; z += (L3[r] - L3[l] * P3[r-l]) % M3; if (z < 0) z += M3;
        }
        return {x,y,z};
    }
    hval get(int l, int r) { return get({l,r}); }
};

void solve() {
    int n;
    string s;
    cin >> n >> s;
    Hasher h1, h2;
    h1.init(s.begin(), s.end());
    h2.init(s.rbegin(), s.rend());
    rep(i,0,n) {
        if (h1.get({0,i,i+n,2*n}) == h2.get(n-i,2*n-i)) {
            string t = s.substr(i,n);
            reverse(t.begin(), t.end());
            cout << t << "\n" << i;
            return;
        }
    }
    cout << -1;
}

signed main() {
    cin.tie(0)->sync_with_stdio(0);
    int t = 1;
    while (t--) solve();
    return 0;
}

标签:P2,P3,后缀,int,M1,M3,M2,abc284F,逆序
From: https://www.cnblogs.com/chenfy27/p/18060726

相关文章

  • 后缀数组学习笔记
    后缀数组学习笔记定义所谓后缀,指的是对于一个字符串\(s\),如果它的下标从\(1\)到\(n\),那么对于\(s\)的一个后缀\(i=s[i\dotsn]\)。所谓后缀数组sa[],就是按照这些后缀的字典序排序后得到的数组。更具体的,后缀数组sa[i]中存储的是字符串\(s\)中排名为\(i\)的后缀的......
  • 从CF1676H2看逆序对的两种求法
    Problem-1676H2-Codeforces思路原问题可以以直接转化成求\(a_i>=a_j(i<j)\)的数量。归并排序原理很直接,归并排序就是为了减少逆序对的数量,所以直接在操作的时候记录减少的数量即可排序后的数组无逆序对,归并排序的合并操作中,每次后段首元素被作为当前最小值取出时......
  • 前中后缀表达式学习笔记
    前言表达式是数学和计算机编程中常见的概念,用于表示运算和计算过程。前缀、中缀和后缀表达式都是不同的方式来表示数学表达式,它们在计算机科学和计算器设计中都有一定的应用。中缀表达式(InfixExpression):这是最常见的数学表达式表示方法,也是人们通常在书写数学公式时使用的方式......
  • 后缀表达式
    一、题目描述P8683[蓝桥杯2019省B]后缀表达式二、算法简析显然,这道题要用贪心思想。想当然的,我们会先进行降序排序,将大的相加,在减去小的。然而,这种想法是错误的。因为这道题要求的是后缀表达式的最大值,为了便于理解,我们转换为中缀表达式的最大值,这里就有了一个隐含条件—......
  • 后缀数组学习笔记 应用篇
    一些后缀数组的应用。利用\(sa\)和\(rk\)数组这类题目通常需要发掘一些性质,转化为求串的字典序最小/大后缀或长度固定的子串。P3809【模板】后缀排序后缀数组板子。P6095[JSOI2015]串分割二分答案串的排名。CF1923FShrink-Reverse转化为求长度为\(len\)的字典......
  • 后缀数组
    虽然这是基础算法,但我已经好几次忘记它怎么写了,反倒是SAM记得很牢。为了避免比赛中因这个爆蛋,我打算仔细梳理一下它的原理。问题:给你一个字符串,你需要求出\(sa_i,rk_i\),其中\(sa_i\)表示排名为\(i\)的后缀,\(rk_i\)表示后缀\(i\)的排名。首先暴力就是直接快排,里面......
  • 【学习笔记】后缀数组(SA)
    前言先把SA给写出来,SAM暂时还没学会,学会了应该也不会写,因为构造过程过于繁琐。本文可能对SA的算法流程和代码实现上的介绍相对简略,主要介绍一些常见用途。约定无特殊说明字符串的下标从\(1\)开始。无特殊说明\(s\)表示字符串,\(n\)表示字符串长度。“后缀\(i\)”......
  • 后缀自动机学习笔记
    用途略。根本思想略。概念阐释endpos:这是一个集合。\(endpos(x)\)代表子串\(x\)在\(s\)中所有结束位置的集合。等价类:这也是一个集合。一个等价类中包含所有\(endpos(i)\)完全相等的子串\(i\)。有如下引理(其实很显然,看了理解了就可以了):同一等价类中,子串......
  • 小苯的逆序对
    小苯的逆序对题目描述小苯有一个长度为$n$的排列$p$。他很想知道这个排列中有多少个逆序对满足互素。形式化的,有多少个满足$(i<j)$且$(a_i>a_j)$且$gcd(a_i,a_j)=1$的$(i,j)$对。输入描述:输入包含两行。第一行一个正整数$n(1\leqn\leq2\times10^5)$......
  • P3157 [CQOI2011] 动态逆序对 题解
    题目链接:动态逆序对常见经典题,理解一个数对逆序对贡献计算即可。对于一个数而言,它在一个序列中的逆序对有两部分贡献,一部分为前面比它严格大的数,另一部分为后面比它严格小的数,有道二莫题也是基于此去考虑的。考虑最开始知道了总逆序数,每次删除一个数逆序数会减少两部分值,显然就......