LightOJ - 1334 Genes in DNA KMP 求贡献思想

Genes in DNA
题意
给一个文本串和一个模式串,求模式串的所有前缀与后缀的组合在文本串里出现次数和。

思路
这题朴素的算法就是把模式串的前缀和后缀组合列出来,跑KMP求出现次数和。显然数据范围不允许,那考虑求贡献的方法,对于文本串中第i个字符,把所有模式串中以这个字符为结尾的前缀 的个数求出来,记为ans1[i],注意,这里的以第i个字符结尾的前缀不是真的 以字符t[i]结尾的前缀,而是类似文本串与模式串kmp匹配时与t[i]匹配,假设某个前缀的长度为len,也就是s[0]…s[len-1]与t[i - len + 1]…t[i]匹配,这样的前缀有ans1[i]个,同样的,把文本串中以第i个字符为开头的后缀ans2[i]求出来,答案就是所有相邻两个位置的前缀数量*后缀数量之和。

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e6 + 7;
char s1[maxn], s2[maxn];
int nex[maxn], pre[maxn], suf[maxn], ans1[maxn], ans2[maxn];
void getnext(char *s, int d[]) {
    int len = strlen(s);
    nex[0] = -1;
    int i = 0, j = -1;
    while (i < len) {
        if(j == -1 || s[i] == s[j]) {
            i++; j++;
            nex[i] = j;  //这里判断了如果s[i],s[j]相等,表示有相同前缀后缀,然后i++,j++了
            d[i] = d[j] + 1;//所以d[i]表示的是以编号为i-1的字符为结尾的前缀的个数,d[i]=d[j]+1的原因是
        }//以编号i-1的*字符*为结尾的前缀的个数原来就有d[j]个,再加上以i-1为*结尾*的前缀的这个字符串,所以是+1个
        else j = nex[j];
    }
}
void kmp(char *t, char *s, int ans[], int p[]) {//文本串 模式串
    int lent = strlen(t), lens = strlen(s), j = 0, i = 0, num = 0;
    while (i < lent && j < lens) {
        if(j == -1 || t[i] == s[j]) {
            i++; j++;
            ans[i - 1] = p[j] - (j == lens);//t[i],s[j]匹配的时候,就把s串以i字符为结尾的前缀传给t,表示s的前缀中以i-1
        }//这个字符为结尾的前缀个数,j==lens的时候要-1是因为题目要求前缀不能是原串
        else j = nex[j];
        if(j == lens) {
            j = nex[j];//要把t串更新完,所以如果s串匹配完了还要继续跑
        }
    }
}
int main()
{
    int t, Case = 1;
    scanf("%d", &t);
    while (t--) {
        scanf("%s%s", s1, s2);
        getnext(s2, pre);//预处理出s串中前缀的数量pre
        int len2 = strlen(s2), len1 = strlen(s1);
        kmp(s1, s2, ans1, pre);
        //倒过来求后缀数量
        reverse(s1, s1 + len1);
        reverse(s2, s2 + len2);
        getnext(s2, suf);
        kmp(s1, s2, ans2, suf);
        ll ans = 0;
        reverse(ans2, ans2 + len1);//倒过来好算答案
        for (int i = 0; i < len1 - 1; i++)
            ans += (ll)ans1[i] * ans2[i + 1];//答案就是t串中相邻的两个字符为结尾的前缀的个数*为开头的后缀的个数
        printf("Case %d: %lld\n", Case++, ans);
    }
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
提供的源码资源涵盖了安卓应用、小程序、Python应用和Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值