首页 > 其他分享 >CF494B Obsessive String KMP+前缀和优化DP

CF494B Obsessive String KMP+前缀和优化DP

时间:2022-09-27 15:57:06浏览次数:80  
标签:子串 CF494B 匹配 前缀 int 位置 KMP Obsessive dp

给一份看起来字数比较少的题解?

题意

给一个字符串 \(s\),和一个字符串 \(t\)。在 \(s\) 中取出任意多个不重叠的子串 (可以有子串没有被取出),使得每个子串都包含 \(t\) ,求方案数。

具体题意见原题面。

思路

  • 由于需要每个子串中都包含 \(t\),必然需要一个字符串匹配算法,kmp 或者 hash 找出来所有的匹配位置即可,代码中用 vector<int> pos 来记录了所有位置。
  • 求方案数考虑下 dp,注意题目图片中的公式,每一小段 \(ab\) 序列,都由一个 \(b_i\) 来结尾。
  • 设计状态:\(dp[i]\) 表示后面子串不取,只考虑前 \(i\) 个字符,第 \(i\) 位作为 \(b_x\) 的方案数。
  • 考虑转移:若 \(i\) 位作为 \(b_x\) ,那么我们需要找到对应的 \(a_x\) ,显然 \(a_x\) 到 \(b_x\) 势必包含一个匹配位置,可以二分或者线性记录找到对应的最近匹配位置 \(p\) 。
    • 如果没有找到一个匹配位置,\(dp[i]=0\) 。
    • 否则有一个显然的方案,整个子串只有一个 ab 序列,即 \(dp[i] = p\) 。
    • 然后考虑从前面的状态转移,设 \(i\) 对应 b 序列前一个 \(b_y\) 在 \(j\) 下标,则 dp[i] += dp[j] * (p - j)
    • 解释一下转移,对于 \(s[j+1,p]\) 位置的所有下标,都可以作为 \(b_x\) 对应的 \(a_x\) ,再用乘法原理计算。
    • 对于任意 \(j \leq p-1\) 都有以上的转移,\(dp[i] =dp[i]+ (\sum_{j=1}^{p-1} (p - j) * dp[j])\)
    • 发现可以前缀和优化,维护 \(i * dp[i]\) 和 \(dp[i]\) 两个前缀和即可。
  • 时间复杂度 \(O(n)\),代码中的二分查找可以优化掉,这里就懒得写了
const int N = 1e5 + 10, mod = 1e9 + 7;
ll dp[N], pre[N], ipre[N];
// dp[i] 表示第 i 位作为 b_j 的方案数。pos 记录匹配起始位置
int main() {
    string s, t;
    IOS;
    cin >> s >> t;
    int n = s.size(), m = t.size();
    s = " " + s, t = " " + t;
    kmp.get_ne(t.c_str(), SZ(t) - 1);
    pos.pb(-m);
    kmp.match(s.c_str(), t.c_str(), n, m);
    for (int i = 1; i <= n; i++) {
        pre[i] = pre[i - 1];
        ipre[i] = ipre[i - 1];
        auto p = *prev(upper_bound(ALL(pos), i - m + 1));
        if (p == pos[0]) continue;
        dp[i] = p;
        dp[i] = (dp[i] + p * pre[p - 1] % mod - ipre[p - 1] + mod) % mod;
        pre[i] += dp[i];
        ipre[i] = (ipre[i] + i * dp[i]) % mod;
        if (pre[i] >= mod) pre[i] -= mod;
    }
    ll ans = 0;
    for (int i = 1; i <= n; i++) ans = (ans + dp[i]) % mod;
    printf("%lld\n", ans);
    return 0;
}

标签:子串,CF494B,匹配,前缀,int,位置,KMP,Obsessive,dp
From: https://www.cnblogs.com/Roshin/p/CF494B.html

相关文章

  • KMP算法,BF算法
    串、BF算法、KMP算法概述需要掌握:1、串的相关概念,串与线性表之间的异同2、顺序串,和链串中串的基本的基本运算算法设计3、模式匹配算法BF、和KMP算法串......
  • KMP 算法实现
    #coding=utf-8defget_next_list(findding_str):#求一个字符串序列每个位置的最长相等前、后缀j=0#最长相等前缀的末位next=[0]#next数组用......
  • KMP算法
    朴素的模式匹配算法朴素算法就是以主串的每一个字符作为子串的开头,与要匹配的字符串(称为模式串)进行匹配,匹配失败则主串退回到这次匹配首位的下一位,重新进行匹配。主......
  • 【学习笔记】KMP字符串匹配
    字符串匹配——KMP算法给定两个字符串s1和s2,询问s2在s1中出现的位置(定义为出现时的第一个字符在s1中的位置)暴力枚举看到字符串匹配(如果你还不会KMP/Hash的话),八成是......
  • kmp+st表
    前言  时隔两年再一次登上账号  本菜鸡尝试回归捏   复习了kmp和st表发现自己没有发过博客代码#include<iostream>#include<cstring>usingnamespaces......
  • KMP&Z函数详解
    KMP一些简单的定义:真前缀:不是整个字符串的前缀真后缀:不是整个字符串的后缀当然不可能这么简单的,来个重要的定义前缀函数:给定一个长度为\(n\)的字符串\(s\),其\(前......
  • KMP算法的底层理解
    KMP的主要思想是当出现字符串不匹配时,可以知道一部分之前已经匹配的文本内容,可以利用这些信息避免从头再去做匹配了。KMP的精髓所在就是前缀表。(下面用next[]数组来表......
  • A Secret HDU - 6153 扩展KMP || KMP
    题目链接:https://vjudge.net/problem/HDU-6153题意求一个串T的所有后缀在串S中出现的次数,最后再求和。扩展KMP解法可以利用拓展KMP求出S的每一个后缀和T的最长公共前......
  • luoguP8085 [COCI2011-2012#4] KRIPTOGRAM 题解(KMP)
    /*给定明文和密文,密文与明文的某个字串格式相同,找出密文出现的最早位置。如:明文aaabcdabc 密文xy ans:3解:容易想到KMP算法。可以发现,密文和对应子串的格式相同......
  • KMP自动机例题(待学习)
    KMP自动机可以在O(1)的时间内计算kmp。KMP自动机数组kmp_auto[i][j]可以表示第i位为'a'+j时的最长前缀长度(此前缀可以包含自身)。kmp[i]数组,表示第i位的最长前缀长度(不含......