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;
}

浙公网安备 33010602011771号