P2679 子串

update on 2021/1/24

题目链接

大致题意

给两个字符串\(A\)\(B\),从字符串 \(A\) 中取出 \(k\) 个互不重叠的非空子串,把这 \(k\) 个子串按照其在字符串 \(A\) 中出现的顺序依次连接起来得到一个新的字符串,求有多少种方案可以使这个新串和字符串\(B\)相等

\(1≤n≤1000,1≤m≤200,1≤k≤m\)

分析

\(f(i,j,k,0/1)\)表示在\(A\)中的前\(i\)个字符,\(B\)中前\(j\)个字符,一共拆了\(k\)个字串,第\(i\)个字符选\(/\)不选的方案数,分类讨论拼接的情况,有显然的转移:

\(f(i,j,k,1) = f(i-1,j-1,k,0)+f(i-1,j-1,k-1,1)+f_(i-1,j-1,k,1)\)

\(f(i,j,k,0) = f(i-1,j,k,1)+f(i-1,j,k,0)\)

再用滚动数组优化一下即可

时间复杂度\(O(nmk)\)

\(code\)

//90pts
#include<bits/stdc++.h>
#define mo 1000000007
using namespace std;
const int MAXN =1005;
int f[1005][110][110][2];
int n,m,k0;
string a,b;
int main(){
	f[0][0][0][0] = 1; 
	cin>>n>>m>>k0;
	cin>>a>>b;
	a = ' '+a;
	b = ' '+b;
	for(int i=1;i<=n;i++){
		f[i][0][0][0] = 1;
		for(int j=1;j<=m;j++){
			for(int k=1;k<=k0;k++){
				if(a[i]==b[j]){
					f[i][j][k][0] = (f[i-1][j][k][1]+f[i-1][j][k][0])%mo;
					f[i][j][k][1] = ((f[i-1][j-1][k-1][0]+f[i-1][j-1][k-1][1])%mo+f[i-1][j-1][k][1])%mo;
				}
				else{
					f[i][j][k][0] = (f[i-1][j][k][1]+f[i-1][j][k][0])%mo;
				}
			}
		}
	}
	cout<<(f[n][m][k0][0]+f[n][m][k0][1])%mo;
}
#include<bits/stdc++.h>
#define mo 1000000007
using namespace std;
const int MAXN =1005;
int f[2][205][MAXN][2];
int n,m,k0;
string a,b;
int main(){
	int now = 1;
	f[0][0][0][0] =  1;
	f[1][0][0][0] =  1;
	cin>>n>>m>>k0;
	cin>>a>>b;
	a = ' '+a;
	b = ' '+b;
	for(int i=1;i<=n;i++){
		for(int j=1;j<=m;j++){
			for(int k=1;k<=k0;k++){
				if(a[i]==b[j]){
					f[now][j][k][0] = (f[now^1][j][k][1]+f[now^1][j][k][0])%mo;
					f[now][j][k][1] = ((f[now^1][j-1][k-1][0]+f[now^1][j-1][k-1][1])%mo+f[now^1][j-1][k][1])%mo;
				}
				else{
					f[now][j][k][0] = (f[now^1][j][k][1]+f[now^1][j][k][0])%mo;
					f[now][j][k][1] = 0;
				}
			}
		}
		now^=1;
	}
	cout<<(f[n&1][m][k0][0]+f[n&1][m][k0][1])%mo;
}
posted @ 2020-10-05 12:51  xcxc82  阅读(70)  评论(0)    收藏  举报