子串
描述
有两个仅包含小写英文字母的字符串 A 和 B。现在要从字符串 A 中取出 k 个互不重叠的非空子串,然后把这 k 个子串按照其在字符串 A 中出现的顺序依次连接起来得到一 个新的字符串,请问有多少种方案可以使得这个新串与字符串 B 相等?注意:子串取出的位置不同也认为是不同的方案。
格式
输入格式
第一行是三个正整数 n,m,k,分别表示字符串 A 的长度,字符串 B 的长度,以及问 题描述中所提到的 k,每两个整数之间用一个空格隔开。第二行包含一个长度为 n 的字符串,表示字符串 A。 第三行包含一个长度为 m 的字符串,表示字符串 B。
输出格式
输出共一行,包含一个整数,表示所求方案数。由于答案可能很大,所以这里要求输 出答案对 1,000,000,007 取模的结果。
样例1
样例输入1
6 3 1
aabaab
aab样例输出1
2
样例2
样例输入2
6 3 2
aabaab
aab样例输出2
7
样例3
样例输入
6 3 3
aabaab
aab样例输出3
7
限制
对于第 1 组数据:1≤n≤500,1≤m≤50,k=1;
对于第 2 组至第 3 组数据:1≤n≤500,1≤m≤50,k=2;
对于第 4 组至第 5 组数据:1≤n≤500,1≤m≤50,k=m;
对于第 1 组至第 7 组数据:1≤n≤500,1≤m≤50,1≤k≤m;
对于第 1 组至第 9 组数据:1≤n≤1000,1≤m≤100,1≤k≤m;
对于所有 10 组数据:1≤n≤1000,1≤m≤200,1≤k≤m。提示
样例 1:aab aab / aab aab
样例 2:a ab aab / a aba ab / a a ba ab / aab a ab
aa b aab / aa baa b / aab aa b
样例 3: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来源
NOIP 2015 提高组 Day 2 第二题
DP题,我竟然不会,QAQ
明明是个不复杂的DP我却想了好久,果然蒟蒻无比
先说一下滚动前的方程式
dp[0/1][i][j][k]表示dp到n的第i个字符,m的第j个字符,选了k个串有多少个情况,第一个0表示不选当前位,1表示选
然后方程式:
dp[0][i][j][k]=dp[0][i-1][j][k]+dp[1][i-1][j][k]
if(n[i]==m[j])dp[1][i][j][k]=dp[1][i-1][j-1][k]+dp[0][i-1][j-1][k-1]+dp[1][i-1][j-1][k-1]
故意写这么大因为我看小字就头晕,找到个字大的才看懂
然后一定要注意初始化,最复杂的一部分,不选第一位要初始化为n在i以前与m[1]相等的字符数量,如果n[i]==m[1],选就初始化为1
其他的看代码就可以懂了,我就不多说了
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<set>
#include<map>
#include<queue>
#include<algorithm>
#include<vector>
#include<cstdlib>
#include<cmath>
#include<ctime>
#include<stack>
#define INF 2100000000
#define ll long long
#define clr(x) memset(x,0,sizeof(x))
#define maxclr(x) memset(x,127,sizeof(x))
using namespace std;
inline int read()
{
char c;
int ret=0;
while(!(c>='0'&&c<='9'))
c=getchar();
while(c>='0'&&c<='9')
{
ret=(c-'0')+(ret<<1)+(ret<<3);
c=getchar();
}
return ret;
}
#define M 1005
#define N 205
#define P 1000000007
int dp[2][N][N],f[2][2][N][N];
int m,n,k,t,sum;
char sn[M],sm[N];
void DP()
{
for(int i=1;i<=n;i++)
{
for(int j=m;j>=2;j--)//倒着推为了滚动
for(int o=1;o<=k;o++)
{
dp[0][j][o]=(dp[0][j][o]+dp[1][j][o])%P;
if(sn[i]==sm[j])
dp[1][j][o]=((dp[1][j-1][o]+dp[0][j-1][o-1])%P+dp[1][j-1][o-1])%P;
else dp[1][j][o]=0;
}
dp[0][1][1]=t;//初始化当前位前m第一位的情况
if(sn[i]==sm[1])//初始化当前位去第一位的情况
{
t++;
dp[1][1][1]=1;
}
else dp[1][1][1]=0;
}
}
int main()
{
freopen("substring.in","r",stdin);
freopen("substring.out","w",stdout);
n=read();m=read();k=read();
scanf("%s\n%s",sn+1,sm+1);
DP();
printf("%d\n",(dp[0][m][k]+dp[1][m][k])%P);
return 0;
}
大概就是这个样子,如果有什么问题,或错误,请在评论区提出,谢谢。