1. 程式人生 > 實用技巧 >#dp#洛谷 2679 子串

#dp#洛谷 2679 子串

題目

有兩個僅包含小寫英文字母的字串 \(A\)\(B\)

現在要從字串 \(A\) 中取出 \(k\) 個互不重疊的非空子串,然後把這 \(k\) 個子串按照其在字串 \(A\) 中出現的順序依次連線起來得到一個新的字串。請問有多少種方案可以使得這個新串與字串 \(B\) 相等?

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


分析

\(dp[i][j]\)表示當前匹配到字串\(B\)的第\(i\)個位置,
且當前為字串\(A\)的第\(j\)個子串的方案數,
那就是新開一個子串或者是這個子串繼續匹配,
所以用字首和優化就可以了


程式碼

#include <cstdio>
#define rr register
using namespace std;
const int mod=1000000007; char s1[1001],s2[201];
int dp[201][201],n,m,k,s[201][201];
inline signed mo(int x,int y){return x+y>=mod?x+y-mod:x+y;}
signed main(){
	scanf("%d%d%d%s%s",&n,&m,&k,s1+1,s2+1);
	dp[0][0]=1;
	for (rr int i=1;i<=n;++i)
	for (rr int j=m;j>=1;--j)
	for (rr int p=k;p>=1;--p)
	    dp[j][p]=mo(dp[j][p],s[j][p]=(s1[i]==s2[j])?mo(s[j-1][p],dp[j-1][p-1]):0);
	return !printf("%d",dp[m][k]);
}