【NOIP2015提高组】子串

https://daniu.luogu.org/problem/show?pid=2679

看到方案数问题直觉就能想到DP,考虑用f(i,j,k)表示A[1...i]取k个子串组成B[1...j]的方案数,发现很难转移,因为不知道之前的方案哪些是还能拼接到结尾的,产生了前效性。

考虑加一维,即

A[1...i]取k个子串组成B[1...j],且末尾子串还可以继续拼接的方案数为:f(i,j,k,0)={
    拼接上一个子串f(i-1,j-1,k,0)+另开新串f(i-1,j-1,k-1,1) (A[i]==B[j]),
    0 (A[i]!=B[j])
}

A[1...i]取k个子串组成B[1...j],且末尾子串已经封闭或末尾根本不是子串的方案数为:f(i,j,k,1)=sum{
    拼接上一个子串然后封闭f(i-1,j-1,k,0) (A[i]==B[j]),
    开一个字符的串f(i-1,j-1,k-1,1) (A[i]==B[j]),
    不用这个字符f(i-1,j,k,1)
}
其实就是f(i,j,k,1)=用这个字符然后封闭f(i,j,k,0)+不用这个字符f(i-1,j,k,1)

特别的,f(i,0,0,1)=1

#include <iostream>
#include <string>
using namespace std;
typedef long long llint;
llint n, m, kk;
string a, b;
const llint c = 1e9 + 7;
llint dp[2][205][205][2];
int main()
{
    ios::sync_with_stdio(false);
    cin >> n >> m >> kk >> a >> b;
    // f(i,j,k,0) = a[i]==b[j] ? f(i-1,j-1,k,0)+f(i-1,j-1,k-1,1) : 0
    // f(i,j,k,1) = f(i,j,k,0) + f(i-1,j,k,1)
    dp[0][0][0][1] = dp[1][0][0][1] = 1; // f(i,0,0,1)=1
    for (int i = 1; i <= n; i++)
    {
        for (int j = 1; j <= m; j++)
        {
            for (int k = 1; k <= kk; k++)
            {
                dp[i & 1][j][k][0] = (a[i - 1] == b[j - 1]) ? dp[(i - 1) & 1][j - 1][k][0] + dp[(i - 1) & 1][j - 1][k - 1][1] : 0;
                dp[i & 1][j][k][1] = dp[i & 1][j][k][0] + dp[(i - 1) & 1][j][k][1];

                while (dp[i & 1][j][k][0] >= c)
                    dp[i & 1][j][k][0] -= c;
                while (dp[i & 1][j][k][1] >= c)
                    dp[i & 1][j][k][1] -= c;
            }
        }
    }
    cout << dp[n & 1][m][kk][1] << endl;
    return 0;
}
时间: 2024-10-20 16:38:42

【NOIP2015提高组】子串的相关文章

刷题总结——子串(NOIP2015提高组)

题目: 题目背景 NOIP2015 提高组 Day2 T2 题目描述 有两个仅包含小写英文字母的字符串 A 和 B .现在要从字符串 A 中取出 k 个互不重叠的非空子串,然后把这 k 个子串按照其在字符串 A 中出现的顺序依次连接起来得到一个新的字符串,请问有多少种方案可以使得这个新串与字符串 B 相等?注意:子串取出的位置不同也认为是不同的方案. 输入格式 第一行是三个正整数 n,m,k,分别表示字符串 A 的长度,字符串 B 的长度,以及问题描述中所提到的 k ,每两个整数之间用一个空格隔

[NOIP2015] 提高组 洛谷P2615 神奇的幻方

题目描述 幻方是一种很神奇的N*N矩阵:它由数字1,2,3,……,N*N构成,且每行.每列及两条对角线上的数字之和都相同. 当N为奇数时,我们可以通过以下方法构建一个幻方: 首先将1写在第一行的中间. 之后,按如下方式从小到大依次填写每个数K(K=2,3,…,N*N): 1.若(K−1)在第一行但不在最后一列,则将K填在最后一行,(K−1)所在列的右一列: 2.若(K−1)在最后一列但不在第一行,则将K填在第一列,(K−1)所在行的上一行: 3.若(K−1)在第一行最后一列,则将K填在(K−1)

洛谷-神奇的幻方-NOIP2015提高组复赛

题目描述 幻方是一种很神奇的N*N矩阵:它由数字1,2,3,……,N*N构成,且每行.每列及两条对角线上的数字之和都相同. 当N为奇数时,我们可以通过以下方法构建一个幻方: 首先将1写在第一行的中间. 之后,按如下方式从小到大依次填写每个数K(K=2,3,…,N*N): 1.若(K−1)在第一行但不在最后一列,则将K填在最后一行,(K−1)所在列的右一列: 2.若(K−1)在最后一列但不在第一行,则将K填在第一列,(K−1)所在行的上一行: 3.若(K−1)在第一行最后一列,则将K填在(K−1)

Noip2015 提高组 Day1

T1神奇的幻方 题目描述 幻方是一种很神奇的N*N矩阵:它由数字1,2,3,……,N*N构成,且每行.每列及两条对角线上的数字之和都相同. 当N为奇数时,我们可以通过以下方法构建一个幻方: 首先将1写在第一行的中间. 之后,按如下方式从小到大依次填写每个数K(K=2,3,…,N*N): 1.若(K−1)在第一行但不在最后一列,则将K填在最后一行,(K−1)所在列的右一列: 2.若(K−1)在最后一列但不在第一行,则将K填在第一列,(K−1)所在行的上一行: 3.若(K−1)在第一行最后一列,则将

[NOIP2015] 提高组 洛谷P2679 子串

题目背景 无 题目描述 有两个仅包含小写英文字母的字符串 A 和 B.现在要从字符串 A 中取出 k 个互不重叠的非空子串,然后把这 k 个子串按照其在字符串 A 中出现的顺序依次连接起来得到一 个新的字符串,请问有多少种方案可以使得这个新串与字符串 B 相等?注意:子串取出 的位置不同也认为是不同的方案. 输入输出格式 输入格式: 输入文件名为 substring.in. 第一行是三个正整数 n,m,k,分别表示字符串 A 的长度,字符串 B 的长度,以及问 题描述中所提到的 k,每两个整数之

[NOIP2015] 提高组 洛谷P2678 跳石头

题目背景 一年一度的“跳石头”比赛又要开始了! 题目描述 这项比赛将在一条笔直的河道中进行,河道中分布着一些巨大岩石.组委会已经选择好了两块岩石作为比赛起点和终点.在起点和终点之间,有 N 块岩石(不含起点和终 点的岩石).在比赛过程中,选手们将从起点出发,每一步跳向相邻的岩石,直至到达 终点. 为了提高比赛难度,组委会计划移走一些岩石,使得选手们在比赛过程中的最短跳 跃距离尽可能长.由于预算限制,组委会至多从起点和终点之间移走 M 块岩石(不能 移走起点和终点的岩石). 输入输出格式 输入格式

[NOIP2015] 提高组 洛谷P2668 斗地主

题目描述 牛牛最近迷上了一种叫斗地主的扑克游戏.斗地主是一种使用黑桃.红心.梅花.方片的A到K加上大小王的共54张牌来进行的扑克牌游戏.在斗地主中,牌的大小关系根据牌的数码表示如下:3<4<5<6<7<8<9<10<J<Q<K<A<2<小王<大王,而花色并不对牌的大小产生影响.每一局游戏中,一副手牌由n张牌组成.游戏者每次可以根据规定的牌型进行出牌,首先打光自己的手牌一方取得游戏的胜利. 现在,牛牛只想知道,对于自己的若干

noip2015提高组

2015的题比2014丧多了. T1--神奇的幻方--然而T1还是挺简单的--简单模拟. #include<iostream> #include<cstdio> using namespace std; int n,a[50][50],x,y; int main() { scanf("%d",&n); x=1;y=(n+1)>>1;a[x][y]=1; for(int i=2;i<=n*n;i++){ if(x==1&&

洛谷 P2540 斗地主(NOIp2015提高组D1T3)

题目描述 牛牛最近迷上了一种叫斗地主的扑克游戏.斗地主是一种使用黑桃.红心.梅花.方片的A到K加上大小王的共54张牌来进行的扑克牌游戏.在斗地主中,牌的大小关系根据牌的数码表示如下:3<4<5<6<7<8<9<10<J<Q<K<A<2<小王<大王,而花色并不对牌的大小产生影响.每一局游戏中,一副手牌由n张牌组成.游戏者每次可以根据规定的牌型进行出牌,首先打光自己的手牌一方取得游戏的胜利. 现在,牛牛只想知道,对于自己的若干