[NOIp2015]子串

\(\mathcal{\color{red}{Description}}\)

有两个仅包含小写英文字母的字符串 \(A\)\(B\)

现在要从字符串 \(A\) 中取出 \(k\) 个互不重叠的非空子串,然后把这 \(k\) 个子串按照其在字符串 \(A\) 中出现的顺序依次连接起来得到一个新的字符串。请问有多少种方案可以使得这个新串与字符串 \(B\) 相等?

注意:子串取出的位置不同也认为是不同的方案。

对于所有 \(10\) 组数据:\(1≤n≤1000,1≤m≤200,1≤k≤m\)

\(\mathcal{\color{red}{Solution}}\)

单纯的我一开始以为是一道状压……然后看到数据范围后是崩溃的……

仔细想了想,好像状压的确会枚举好多智障的冗余状态……那么就开始考虑正常向的\(DP\)……设\(dp_{i,j,k}\)表示\(A\)中匹配到第\(i\)位,\(B\)中匹配到第\(j\)位,共用了\(k\)个子串的方案数。那么状态转移方程很显然就是\(dp_{i,j,k} = (dp_{i-1,j-1,k} + dp_{i - 1, j - 1, k - 1}) \times [A_i = B_j]\)……

但想了想,发现是不对的……因为事实上我们没有考虑上一位没有选这种情况……于是我就不会惹……于是选择看题解\(OTZ\)

然后发现自己被秀了一脸\(qwq\)

我们考虑用两个\(DP\)数组来记录状态,\(f_{i,j,k}\)表示\(A\)中匹配到第\(i\)位,\(B\)中匹配到第\(j\)位,共用了\(k\)个子串,\(A_i\)这一位一定要用的的方案数。\(dp_{i,j,k}\)表示\(A\)中匹配到第\(i\)位,\(B\)中匹配到第\(j\)位,共用了\(k\)个子串,\(A_i\)这一位可用可不用的方案数。

那么转移方程就是\[f_{i,j,k} = (dp_{i-1,j-1,k-1} + f_{i-1,j-1,k}) \times [A_i = B_j]\]\[dp_{i,j,k} = dp_{i-1,j,k}+f_{i,j,k}\]第一个方程是基于是否和上一位连成一串得来的,第二个方程是基于是否选\(A_i\)的得来的。

滚啊滚啊~

#include <cstdio>
#include <cstring>
#include <iostream>
#define MAXN 1010
#define MAXM 210
#define mod 1000000007

using namespace std ;
char A[MAXN], B[MAXM] ; int i, j, k, d ;
int N, M, K, dp[2][MAXM][MAXM], f[2][MAXM][MAXM];

int main(){
    cin >> N >> M >> K ; dp[0][0][0] = 1 ;
    for(i = 1; i <= N; i ++) cin >> A[i] ;
    for(i = 1; i <= M; i ++) cin >> B[i] ;
    for(d = i = 1; i <= N; i ++, d ^= 1){
        dp[d][0][0] = 1 ;
        for(j = 1; j <= M; j ++)
            for(k = 1; k <= K ;k ++){
                if(A[i] == B[j]) f[d][j][k] = (dp[d ^ 1][j - 1][k - 1] + f[d ^ 1][j - 1][k]) % mod ;
                else f[d][j][k] = 0 ;
                dp[d][j][k] = (dp[d ^ 1][j][k] + f[d][j][k]) % mod ;
            }
    }
    cout << dp[N & 1][M][K]% mod ;
}

一点想法:

突然发现不会做的\(DP\)和人生中好多事情都一样。总是缺乏迎难而上的勇气,总是在获得了不属于自己的东西之后沾沾自喜,总是在事情发生完了再追悔莫及。

唉,人啊…

转载于:https://www.cnblogs.com/pks-t/p/9407275.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值