首页 > 其他分享 >P6216 回文匹配 解题报告

P6216 回文匹配 解题报告

时间:2023-01-09 21:46:36浏览次数:39  
标签:P6216 匹配 int s2 s1 mid 解题 回文

Description

对于一对字符串 $(s_1,s_2)$,若 $s_1$ 的长度为奇数的子串 $(l,r)$ 满足 $(l,r)$ 是回文的,那么 $s_1$ 的“分数”会增加 $s_2$ 在 $(l,r)$ 中出现的次数。

现在给出一对 $(s_1,s_2)$,请计算出 $s_1$ 的“分数”。

Solution

先考虑最暴力的做法。枚举子区间,暴力匹配,$O(n^4)$。将匹配改成 KMP,可以优化到 $O(n^3)$。优化区间的枚举方法,边扫边匹配,可以优化到 $O(n^2)$。

我们可以一开始对 $s1, s2$ 跑一遍 KMP 匹配,将匹配成功的部分的左端点 $a_i$ 设为 $1$, 其它点设为 $0$, 问题转换为区间和。

看到回文子区间,应该能想到 manachar 算法。考虑答案的计算方式,设以 $i$ 为对称点的最长回文区间为 $[l,r]$, 我们实际上就是在求 $s[l:r] + s[l+1:r-1] + s[l+2][r-2] ... + s[i:i]$ 的答案。但是会有不合法情况,对半取就是一个经典的前缀和问题。由于会有不合法的情况,我们可以一开始将 $r$ 更新为 $r - m + 1$, 然后将 $(l+r)/2$ 作为计算时新的对称点(只是计算,并不是真的对称点),就不会有不合法情况了。

CODE

#include<bits/stdc++.h>
using namespace std;
#define uint unsigned int
inline int read() {
    int x = 0, f = 1; char c = getchar();
    while (c < '0' || c > '9') {if (c == '-') f = -f; c = getchar();}
    while (c >= '0' && c <= '9') {x = (x << 3) + (x << 1) + (c ^ 48); c = getchar();}
    return x * f;
}
const int N = 3e6 + 10;
int n, m, nxt[N], a[N];
char s[N], t[N];
inline void kmp() {
    nxt[1] = 0;
    for (int i = 2, j = 0; i <= m; ++ i) {
        while (j && t[i] != t[j+1]) j = nxt[j];
        if (t[i] == t[j+1]) j ++;
        nxt[i] = j;
    }
    for (int i = 1, j = 0; i <= n; ++ i) {
        while (j && s[i] != t[j+1]) j = nxt[j];
        if (s[i] == t[j+1]) ++ j;
        if (j == m) a[i-m+1] = 1; 
    }
}
int p[N];
inline void manachar() {
    int mx = 0, id = 0;
    for (int i = 1; i <= n; ++ i) {
        if (i < mx) p[i] = min(mx - i, p[2*id-i]);
        else p[i] = 1;
        while (s[i+p[i]] == s[i-p[i]]) ++ p[i];
        if (i + p[i] - 1 > mx) mx = i + p[i] - 1, id = i; 
    }
}
uint s1[N], s2[N];
inline void solve() {
    uint ans = 0, ans2 = 0;
    for (int i = 1; i <= n; ++ i) s1[i] = s1[i-1] + a[i], s2[i] = s2[i-1] + a[i] * i;
    for (int i = 1; i <= n; ++ i) {
        int l = i - p[i] + 1, r = i + p[i] - m;
        if (l > r) continue;
        int mid = l + r >> 1;
        ans += s2[mid] - s2[l-1] - (s1[mid] - s1[l-1]) * (l - 1);
        if (r != mid) ans += (s1[r] - s1[mid]) * (r + 1) - (s2[r] - s2[mid]); 
    }
    printf("%u\n", ans);
}
int main () {
    n = read(); m = read();
    scanf ("%s", s + 1); scanf("%s", t + 1);
    s[0] = '$'; s[n+1] = t[n+1] = '#';
    kmp(); manachar(); solve();
    return 0;
}
View Code

 

标签:P6216,匹配,int,s2,s1,mid,解题,回文
From: https://www.cnblogs.com/CikL1099/p/17038588.html

相关文章

  • 补题:回文质数
    本质上这题还是有关筛素数,但是增多了一些细节,还是值得注意和思考一下的题目大意为在一个有限范围内求出[a,b]内即是回文数又是质数的数并打出一开始是也是想先把质数筛......
  • CF808G Anthem of Berland 解题报告
    Description给定$s$串和$t$串,其中$s$串包含小写字母和问号,$t$串只包含小写字母。假设共有$k$个问号。你需要给把每个问号变成一个小写字母,共有$26^k$种可能......
  • 「解题报告」CF1442D Sum
    首先可以发现,如果我们选了两堆且两堆均没选完,那么如果我们将较小的一个改成选较大的一个的下一个,这样一直选一定是更优的,最后肯定会使一些堆全部选完,一些堆没选,一个堆选了......
  • P3426 [POI2005]SZA-Template 解题报告
    一道思维难度较高的KMP题目,对border性质要求较高。Description给定一个字符串$s$,求长度最小的前缀$t$满足"匹配"完$s$,这里的"匹配"可以看原题目,不太好描述,建议......
  • P7114 [NOIP2020] 字符串匹配 解题报告
    ~~NOIP的蓝题果然还是好难啊啊啊啊~~前言:作为一道NOIP的真题,这道题放在T2难度并不是特别大,不过考点还是比较偏的,扩展KMP和树状数组的组合,并且还带有一定的思维难度,......
  • AtCoder Beginner Conest 284 解题报告
    AtCoderBeginnerConest284解题报告\(\text{ByDaiRuiChen007}\)\(\text{ContestLink}\)A.SequenceofStrings模拟,时间复杂度\(\Theta(n)\)#include<bits/stdc......
  • 解题报告目录
    解怪题选择性报告(22.6.5~)关键词:低配版解题报告。22.10.10T3mountains关键词:隐藏。22.10.9T4种树关键词:隐藏。图论上的状压DP计数问题关键词:如题。22......
  • LeetCode 5_最长回文子串
    LeetCode5:最长回文子串题目给你一个字符串s,找到s中最长的回文子串。如果字符串的反序与原始字符串相同,则该字符串称为回文字符串。示例1:输入:s="babad"输出:"b......
  • CF 1770 解题报告
    CF1770.GoodBye2022,2023isNear晚上十点三十五开打,十一点多就睡觉了,只做了A、C题,其他题都是VP的。感觉质量很高,签到题A题都卡了我一会。A.KoxiaandWhiteboard......
  • LOJ 数列分块入门 9 题解题报告
    LOJ数列分块入门9题解题报告\(\text{ByDaiRuiChen007}\)I.数列分块入门1题目大意\(\text{Link}\)维护一个长度为\(n\)的序列,支持区间加,单点查值思路分析简......