UOJ #149. 【NOIP2015】子串
有两个仅包含小写英文字母的字符串 A 和 B。
现在要从字符串 A 中取出 k 个互不重叠的非空子串,然后把这 k 个子串按照其在字符串 A 中出现的顺序依次连接起来得到一个新的字符串。请问有多少种方案可以使得这个新串与字符串 B 相等?
注意:子串取出的位置不同也认为是不同的方案。
输入格式
第一行是三个正整数 n,m,k,分别表示字符串 A 的长度,字符串 B 的长度,以及问题描述中所提到的 k,每两个整数之间用一个空格隔开。
第二行包含一个长度为 n 的字符串,表示字符串 A。
第三行包含一个长度为 m 的字符串,表示字符串 B。
输出格式
输出共一行,包含一个整数,表示所求方案数。
由于答案可能很大,所以这里要求输出答案对 1000000007 取模的结果。
样例一
input
6 3 1 aabaab aab
output
2
样例二
input
6 3 2 aabaab aab
output
7
样例三
input
6 3 3 aabaab aab
output
7
explanation
所有合法方案如下:(加下划线的部分表示取出的子串)
样例一:aab aab / aab aab
样例二:a ab aab / a aba ab / a a ba ab / aab a ab / aa b aab / aa baa b / aab aa b
样例三:a a b aab / a a baa b / a ab a a b / a aba a b / a a b a a b / a a ba a b / aab a a b
限制与约定
测试点编号 | n的规模 | m的规模 | k的规模 |
---|---|---|---|
1 | n≤500 | m≤50 | k=1 |
2 | k=2 | ||
3 | |||
4 | k=m | ||
5 | |||
6 | k≤m | ||
7 | |||
8 | n≤1000 | m≤100 | |
9 | |||
10 | m≤200 |
时间限制:1s
空间限制:128MB
下载
题目链接:http://uoj.ac/problem/149
解题报告
显然的DP题,
定义状态转移方程f[i][j][k],
表示在A串中的第i个位置,在B串中的第j个位置,B[1...j]划分成k段的方案数.
再定义状态转移方程f[i][j][k],
表示s[i][j][k]=∑(l=1,i)f[l][j][k].
对于方程f[i][j][k],
当A[i]==B[j]时,考虑将B[i]划分入前一段子串或者新建一段子串,
(1).划分入前一段子串的方案数为f[i-1][j-1][k].
(2).新建一段子串的总方案数为s[i-1][j-1][k-1].
所以,f[i][j][k]=f[i-1][j-1][k]+s[i-1][j-1][k-1].
当A[i]!=B[j]时,自然f[i][j][k]=0.
方程为,
f[i][j][k]=A[i]==B[j]?f[i-1][j-1][k]+s[i-1][j-1][k-1].
所以,总时间复杂度为O(n*m*k).
ans=s[n][m][k].
但是,空间复杂度为O(n*m*k),
好像很不OK,
可以发现,
(1).f[i][j][k]只与f[i-1][j-1][k],s[i-1][j-1][k-1]有关.
(2).s[i][j][k]只与s[i-1][j][k],f[i][j][k]有关.
考虑用滚动数组.
空间复杂度压成O(m*k).
方程为,
f[now][j][l]=A[i]==B[j]?(f[now^1][j-1][l]+s[now^1][j-1][l-1]):0.
s[now][j][l]=s[now^1][j][l]+f[now][j][l].
AC代码:
#include<cstdio> #include<iostream> #define MOD 1000000007 #define FOR(i,s,t) for(register int i=s;i<=t;++i) #define ll long long using namespace std; ll f[2][1011][1011]; ll s[2][1011][1011]; int n,m,k,now; char A[1011],B[1011]; int main(){ scanf("%d%d%d",&n,&m,&k); scanf("%s",A+1); scanf("%s",B+1); s[0][0][0]=1; FOR(i,1,n){ now^=1; s[now][0][0]=1; FOR(j,1,m) FOR(l,1,k){ A[i]==B[j]?f[now][j][l]=(ll)(f[now^1][j-1][l]+s[now^1][j-1][l-1])%MOD:f[now][j][l]=0; s[now][j][l]=(ll)(s[now^1][j][l]+f[now][j][l])%MOD; } } cout<<s[n&1][m][k]<<endl; return 0; }