codeforces 494B kmp+dp

本文介绍了一个字符串匹配问题:给定两个字符串s和t,在s中找出所有不重叠的子串,使得每个子串都包含t作为子串,并计算合法子串组合的数量。通过KMP算法预处理并实现动态规划求解。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Hamed has recently found a string t and suddenly became quite fond of it. He spent several days trying to find all occurrences of t in other strings he had. Finally he became tired and started thinking about the following problem. Given a string s how many ways are there to extract k ≥ 1 non-overlapping substrings from it such that each of them contains string t as a substring? More formally, you need to calculate the number of ways to choose two sequences a1, a2, …, ak and b1, b2, …, bk satisfying the following requirements:
k ≥ 1

t is a substring of string saisai + 1… sbi (string s is considered as 1-indexed).
As the number of ways can be rather large print it modulo 109 + 7.
Input
Input consists of two lines containing strings s and t (1 ≤ |s|, |t| ≤ 105). Each string consists of lowercase Latin letters.
Output
Print the answer in a single line.
Sample test(s)
input
ababa
aba
output
5
input
welcometoroundtwohundredandeightytwo
d
output
274201
input
ddd
d
output
12
题目意思让我读了好久,可怜我渣渣英语。 题意大概是 先给你一个串 S 然后再给你一个串 T ,那么如果一个集合,这个集合里面有一些串 分别为 a1,a2,a3,a4…ax
如果 这些串都属于 S的子串并且 这些串不能含有相同的第某个字符,即是不能重复 且 T 也是这些串每个串的子串,那么这个集合就是一个合法集合,问有多少个合法集合
举个例子吧 ababa 和 aba 那么符合条件的集合 有5个 分别 是 { aba } ,{abab} ,{ababa}. {baba},{aba}.
而且这是子串 就是中间不能隔开的是完整的,substring 子串,subquence 子序列 子序列可以不连续

f[n]代表前n个字符来划分,有多少种划分方式,sum[i]代表1到i的f的和,
先用kmp记录每个t子串的开始位置。然后根据这样的位置进行转移
f[i] 代表在匹配串里选了i作为匹配串的一部分加上前面l个字符取法的情况。sum代表前面有多少种划分方法。f[i]=f[i-1] 上一步有的划分方法肯定都有。加上当前步的划分方法。 当前的划分方法来源于,上一个匹配串确定了 加上 l种取法。加上i本身,所有的原有取法加上i本身就可以多算一种取法。

#include <bits/stdc++.h>
using namespace std;
char s[200005],t[200005];
int len1,len2,f[2000005],sum[200005],p[1200005],pd[200005];
const int Mod = 1e9+7;

int read()
{
    int t=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9')
    {
        if(ch=='-') f=-1;ch=getchar();
        while('0'<=ch&&ch>='9') 
        {
            t=t*10+ch-'0';ch=getchar();
        }
        return t*f;
    }
}

void kmp()
{
    p[1]=0;int j=0;
    for(int i=2;i<=len2;i++)
    {
        while(j>0&&t[j+1]!=t[i]) j=p[j];
        if(t[j+1]==t[i]) j++;
        p[i]=j;
    }
    j=0;
    for(int i=1;i<=len1;i++)
    {
        while(j>0&&t[j+1]!=s[i]) j=p[j];
        if(t[j+1]==s[i]) j++;
        if(j==len2)
            pd[i]=i-len2+1;
    }
    for(int i=1;i<=len1;i++)
    {
        if(!pd[i]) pd[i]=pd[i-1];
    }
}

int main()
{
    scanf("%s",s+1);scanf("%s",t+1);
    len1=strlen(s+1);len2=strlen(t+1);
    kmp();
    for(int i=1;i<=len1;i++)
    {
        f[i]=f[i-1];
        int l=pd[i];
        if(!l) continue;
        (f[i]+=(sum[l-1]+l)%Mod)%=Mod;
        sum[i]=(sum[i-1]+f[i])%Mod;
    }
    printf("%d\n",f[len1] );
}
Codeforces Gym 101630 是一场编程竞赛,通常包含多个算法挑战问题。这些问题往往涉及数据结构、算法设计、数学建模等多个方面,旨在测试参赛者的编程能力和解决问题的能力。 以下是一些可能出现在 Codeforces Gym 101630 中的题目类型及解决方案概述: ### 题目类型 1. **动态规划(DP)** 动态规划是编程竞赛中常见的题型之一。问题通常要求找到某种最优解,例如最小路径和、最长递增子序列等。解决这类问题的关键在于状态定义和转移方程的设计[^1]。 2. **图论** 图论问题包括最短路径、最小生成树、网络流等。例如,Dijkstra 算法用于求解单源最短路径问题,而 Kruskal 或 Prim 算法则常用于最小生成树问题[^1]。 3. **字符串处理** 字符串问题可能涉及模式匹配、后缀数组、自动机等高级技巧。KMP 算法和 Trie 树是解决此类问题的常用工具[^1]。 4. **数论与组合数学** 这类问题通常需要对质数、模运算、排列组合等有深入的理解。例如,快速幂算法可以用来高效计算大数的模幂运算[^1]。 5. **几何** 几何问题可能涉及点、线、多边形的计算,如判断点是否在多边形内部、计算两个圆的交点等。向量运算和坐标变换是解决几何问题的基础[^1]。 ### 解决方案示例 #### 示例问题:动态规划 - 最长递增子序列 ```python def longest_increasing_subsequence(nums): if not nums: return 0 dp = [1] * len(nums) for i in range(len(nums)): for j in range(i): if nums[i] > nums[j]: dp[i] = max(dp[i], dp[j] + 1) return max(dp) # 示例输入 nums = [10, 9, 2, 5, 3, 7, 101, 18] print(longest_increasing_subsequence(nums)) # 输出: 4 ``` #### 示例问题:图论 - Dijkstra 算法 ```python import heapq def dijkstra(graph, start): distances = {node: float('infinity') for node in graph} distances[start] = 0 priority_queue = [(0, start)] while priority_queue: current_distance, current_node = heapq.heappop(priority_queue) if current_distance > distances[current_node]: continue for neighbor, weight in graph[current_node].items(): distance = current_distance + weight if distance < distances[neighbor]: distances[neighbor] = distance heapq.heappush(priority_queue, (distance, neighbor)) return distances # 示例输入 graph = { 'A': {'B': 1, 'C': 4}, 'B': {'A': 1, 'C': 2, 'D': 5}, 'C': {'A': 4, 'B': 2, 'D': 1}, 'D': {'B': 5, 'C': 1} } start = 'A' print(dijkstra(graph, start)) # 输出: {'A': 0, 'B': 1, 'C': 3, 'D': 4} ``` #### 示例问题:字符串处理 - KMP 算法 ```python def kmp_failure_function(pattern): m = len(pattern) lps = [0] * m length = 0 # length of the previous longest prefix suffix i = 1 while i < m: if pattern[i] == pattern[length]: length += 1 lps[i] = length i += 1 else: if length != 0: length = lps[length - 1] else: lps[i] = 0 i += 1 return lps def kmp_search(text, pattern): n = len(text) m = len(pattern) lps = kmp_failure_function(pattern) i = 0 # index for text j = 0 # index for pattern while i < n: if pattern[j] == text[i]: i += 1 j += 1 if j == m: print("Pattern found at index", i - j) j = lps[j - 1] elif i < n and pattern[j] != text[i]: if j != 0: j = lps[j - 1] else: i += 1 # 示例输入 text = "ABABDABACDABABCABAB" pattern = "ABABCABAB" kmp_search(text, pattern) # 输出: Pattern found at index 10 ``` ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值