[2015NOIP] 子串
子串
【问题描述】
有两个仅包含小写英文字母的字符串A和B。
现在要从字符串A中取出k个 互不重叠 的非空子串,
然后把这k个子串按照其在字符串A中出现的顺序 依次连接 起来得到一个新的字符串,
请问有多少种方案可以使得这个新串与字符串B相等?注意:子串取出的位置不同也认为是不同的方案。
【输入格式】
第一行是三个正整数n,m,k,分别表示字符串A的长度,字符串B的长度,以及问题描述中所提到的k,
每两个整数之间用一个空格隔开。
第二行包含一个长度为n的字符串,表示字符串A。
第三行包含一个长度为m的字符串,表示字符串B。
【输出格式】
输出共一行,包含一个整数,表示所求方案数。
由于答案可能很大,所以这里要求输出答案对1,000,000,007取模的结果。
【样例】
输入
6 3 1
aabaab aab
输出
2
由于子串按序依次连接 考虑dp
方程 dp[i][j][k]=dp[i][i-1][k] (A[i]!=B[j])
dp[i][j][k]=dp[i-1][j][k]+dp[i-1][j-1][k]+dp[i-1][j-1][k-1]-dp[i-2][j-1][k] (A[i]==B[j])
/*by dudu 2016-6-8 substring*/ #include<iostream> #include<cstdio> using namespace std; #define P 1000000007 int N,M,K,cur; char A[1010],B[510]; int dp[2][1010][510]; int main() { //freopen("2015substring.in","r",stdin),freopen("2015substring.out","w",stdout); scanf("%d%d%d",&N,&M,&K); scanf("%s %s",A+1,B+1); for(int i=0;i<=N;i++) dp[0][i][0]=1; for(int k=1;k<=K;k++) { cur^=1; for(int i=0;i<=N;i++) dp[cur][i][k-1]=0; for(int j=k;j<=M;j++) { for(int i=j;i<=N;i++) { if(A[i]==B[j]) { dp[cur][i][j]=(dp[cur][i-1][j]+dp[cur][i-1][j-1])%P; dp[cur][i][j]=(dp[cur][i][j]+dp[cur^1][i-1][j-1])%P; if(i>=2) dp[cur][i][j]=(dp[cur][i][j]-dp[cur][i-2][j-1]+P)%P; } else dp[cur][i][j]=dp[cur][i-1][j]; } } } cout<<dp[cur][N][M]; return 0; }

浙公网安备 33010602011771号