[NOIp2015]子串

Description

Luogu2679
\(A\)中选出\(k\)个非空子串且连起来是\(B\)的方案数。

Solution

这个题可以仿照最长公共子序列来定义状态\(f_{i,j,k}\)表示\(A\)串的前\(i\)个和\(B\)串的前\(j\)个匹配,且用了\(k\)个子串,并且必须选\(A_i\)。但是这样并不是很好转移。
所以我们添加一个辅助状态\(s_{i,j,k}\)表示\(A\)串的前\(i\)个和\(B\)串的前\(j\)个匹配,且用了\(k\)个子串,但是不一定选\(A_i\)。于是就有如下几种转移:

\(A_i = B_j\),则\(f_{i,j,k} = f_{i-1,j-1,k} + s[i-1][j-1][k-1]\)(分别对应\(A_i\)\(A_{i-1}\)组合成一个子串或者是单独成一个子串),否则\(f_{i,j,k} = 0\)
而无论如何,\(s_{i,j,k} = f_{i, j, k} + s_{i-1,j,k}\)

Code

#include <cstdio>

typedef long long ll;
const int N = 1010;
const int M = 210;
const ll MOD = 1e9 + 7;

ll f[M][M][2];
char a[N], b[M];
int n, m, k;

int main() {
    scanf("%d%d%d", &n, &m, &k);
    scanf("%s", a+1); scanf("%s", b+1);
    f[0][0][0] = f[0][0][1] = 1;
    for (int i = 1; i <= n; ++i)
        for (int j = m; j; --j)
            for (int K = k; K; --K) {
                if (a[i] == b[j])
                    f[j][K][0] = (f[j-1][K][0] + f[j-1][K-1][1]) % MOD;
                else f[j][K][0] = 0;
                
                f[j][K][1] = (f[j][k][1] + f[j][K][0]) % MOD;
            }
    printf("%lld\n", f[m][k][1] % MOD);
}

Note

这个题我一开始提交的时候写的是%I64d错了一次,后来又因为忘记取模错了一次。这些小问题还是要仔细。

猜你喜欢

转载自www.cnblogs.com/wyxwyx/p/noip201522.html
今日推荐