首页 > 编程语言 >武汉大学2022级新生程序设计竞赛 F - 最短公共超串 // kmp

武汉大学2022级新生程序设计竞赛 F - 最短公共超串 // kmp

时间:2022-10-15 21:47:56浏览次数:74  
标签:子串 len next 级新生 2022 kmp 字符串

题目来源:“帆软杯”武汉大学2022级新生程序设计竞赛 F

题目链接:F-最短公共超串


题意

给定两个字符串\(a\)和\(b\),求:一个同时以\(a\)和\(b\)作为子串的最短字符串。

数据范围:\(|a|,|b|\le2·10^5\).

思路:kmp

若有\(b\)为\(a\)的子串,那么\(a\)就是答案;若有\(a\)为\(b\)的子串,那么\(b\)就是答案。快速判断一个字符串中是否存在等于另一个字符串的子串,可以用kmp算法。

若不存在以上两种情况,那么答案应该是\(a\)在前\(b\)在后,去掉中间重叠部分,或者\(b\)在前\(a\)在后,去掉中间重叠部分的形式。

对于\(a\)在前\(b\)在后的情况,实际上我们需要找出最长的同时为\(a\)后缀和\(b\)前缀的公共子串长度\(len_1\),那么答案就是\(|a|+|b|-len_1\)。将\(b\)和\(a\)按顺序拼接起来,得到一个新的字符串,记为\(c\),对\(c\)求一次\(next\)数组,那么\(next[|a|+|b|]\)就是\(c\)最大的相等前后缀长度,同时也是要求的\(len_1\)。

相对应的,可以得到\(b\)在前\(a\)在后的情况,求得\(len_2\)。我们要令答案尽量短,就希望重叠部分尽量长,因此取重叠部分较长的那种情况即可。

时间复杂度:\(O(|a|+|b|)\).

代码

#include <bits/stdc++.h>
#define endl '\n'
using namespace std;

const int N = 200010;

int n, m, ne[N << 1];
char a[N], b[N], c[N << 1];

int get_next(char s[], int n)
{
    ne[1] = 0;
    for(int i = 2, j = 0; i <= n; i++) {
        while(j && s[i] != s[j + 1]) j = ne[j];
        if(s[i] == s[j + 1]) ++ j;
        ne[i] = j;
    }
    return ne[n];
}

bool inString(char s1[], int n1, char s2[], int n2)
{
    for(int i = 1, j = 0; i <= n1; i++) {
        while(j && s1[i] != s2[j + 1]) j = ne[j];
        if(s1[i] == s2[j + 1]) ++ j;
        if(j == n2) return true;
    }
    return false;
}

int main()
{
    cin.tie(0);
    ios::sync_with_stdio(false);

    cin >> a + 1 >> b + 1;
    n = strlen(a + 1), m = strlen(b + 1);

    // b为a的子串
    get_next(b, m);
    if(inString(a, n, b, m)) {
        cout << a + 1 << endl;
        return 0;
    }

    // a为b的子串
    get_next(a, n);
    if(inString(b, m, a, n)) {
        cout << b + 1 << endl;
        return 0;
    }

    // a在前,b在后,去掉重叠部分
    for(int i = 1; i <= m; i++) c[i] = b[i];
    for(int i = 1; i <= n; i++) c[m + i] = a[i];
    int len1 = get_next(c, n + m);  // 同时为a后缀和b前缀的最大子串长度
 
    // b在前,a在后,去掉重叠部分
    for(int i = 1; i <= n; i++) c[i] = a[i];
    for(int i = 1; i <= m; i++) c[n + i] = b[i];
    int len2 = get_next(c, n + m);  // 同时为b后缀和a前缀的最大子串长度
 
    if(len1 >= len2) {
        cout << a + 1;
        for(int i = len1 + 1; i <= m; i++) cout << b[i];
    } else {
        cout << b + 1;
        for(int i = len2 + 1; i <= n; i++) cout << a[i];
    }

    return 0;
}

标签:子串,len,next,级新生,2022,kmp,字符串
From: https://www.cnblogs.com/jakon/p/16795107.html

相关文章

  • 2022-2023-1 20221419 《计算机基础与程序设计》第7周学习总结
    2022-2023-120221419《计算机基础与程序设计》第7周学习总结作业信息班级:[2022-2023-1-计算机基础与程序设计]https://edu.cnblogs.com/campus/besti/2022-2023-1-CFAP......
  • 2022-2023-1 20221306 《计算机基础与程序设计》第七周学习总结
    作业信息班级链接:https://edu.cnblogs.com/campus/besti/2022-2023-1-CFAP作业要求:https://www.cnblogs.com/rocedu/p/9577842.html#WEEK07作业目标:子程序与参数,抽象数据......
  • 2022NOIPA层联测9
    A.泰山压顶code#include<cstring>#include<algorithm>#include<cstdio>#include<cmath>#include<queue>#include<map>#include<set>usingnamespacestd;typ......
  • 2022-10-15 react+react-draft-wysiwyg之富文本编译器安装过程
    npminstall--savereact-draft-wysiwygnpminstall--savedraft-jsnpminstall--savedraftjs-to-htmlnpminstall--savehtml-to-draftjs需要引入以下文......
  • 2022-2023-1 20221418 《计算机基础与程序设计》第七周学习总结
    2022-2023-120221418《计算机基础与程序设计》第七周学习总结作业信息这个作业属于哪个课程(2022-2023-1-计算机基础与程序设计)这个作业要求在哪里(2022-2023......
  • 47th2022/10/15 模拟赛总结34
    这次打得不太好AC了一题,但是T2疏忽了,0的情况忘掉,导致爆0然后后面两题并没有拿分,一大损失后来发现T3是可以拿一定分数的,思考了很多,尤其是DP,但是状态设出来又发现没用,不......
  • 2022-2023 20221403《计算机基础与程序设计》第七周学习总结
    学期(如2022-2023-1)学号20221410《计算机基础与程序设计》第七周学习总结作业信息**教材学习内容总结**了解栈和队列的运行方式;明白了列表的链式结构;注意列表不是数......
  • kmp算法快速简易理解
    1.求next数组1.1定义什么是最长相等前后缀长度?​ 字符串ab的最长相等前后缀为空集,长度为0​ 字符串aba的最长相等前后缀为a,长度为1​ 字符串aaa的最长相等前......
  • 2022/10/15 总结
    写在最前面个人认为这次考试的时间安排比较合理:花\(30min\)写完暴力思考第一题无果后开始写第二题,花费\(90min\)写完调完,并且写了另一份暴力和数据生成器,完整对拍过,第......
  • 江南信息学第六周练习20221014
    1001:给定一个字符,用它构造一个对角线长3个字符,倾斜放置的菱形1002:一只大象口渴了,要喝20升水才能解渴,但现在只有一个深h厘米,底面半径为r厘米的小圆桶(h和r都是整数)。问大......