您的位置:首页 > 其它

[NOIP2015提高组]子串 DP

2017-11-02 19:34 330 查看
题目描述

有两个仅包含小写英文字母的字符串 A 和 B。现在要从字符串 A 中取出 k 个互不重叠的非空子串,然后把这 k 个子串按照其在字符串 A 中出现的顺序依次连接起来得到一 个新的字符串,请问有多少种方案可以使得这个新串与字符串 B 相等?注意:子串取出 的位置不同也认为是不同的方案。

题解:

简单DP。状态表示以及转移见代码。

代码:

#include<bits/stdc++.h>
using namespace std;
#define LL long long
#define pa pair<int,int>
const int Maxn=1010,Maxm=210,Maxk=210,mod=1e9+7;
const int inf=2147483647;
int read()
{
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+(ch^48);ch=getchar();}
return x*f;
}
int n,m,K,pos[26][Maxm],len[26];
char A[Maxn],B[Maxm];
int f[Maxm][Maxk],g[2][Maxm][Maxk];
//f[j][k] B串匹配到j 分了k段 的方案数
//g[j][k] B串匹配到j 分了k段 且上一位有选的方案数
int main()
{
n=read();m=read();K=read();
scanf("%s%s",A+1,B+1);
for(int i=1;i<=m;i++)pos[B[i]-'a'][++len[B[i]-'a']]=i;
f[0][0]=1;
int now=0;
for(int i=1;i<=n;i++)
{
int x=A[i]-'a';now^=1;
memset(g[now],0,sizeof(g[now]));
for(int j=1;j<=len[x];j++)
{
int p=pos[x][j],lim=min(p,K);//匹配到p
for(int k=1;k<=lim;k++)//分了k段
g[now][p][k]=(f[p-1][k-1]+g[now^1][p-1][k])%mod; //新分一段 和前面的一段合在一起
}
int lim1=min(i,m),lim2=min(i,K);
for(int j=0;j<=lim1;j++)
for(int k=0;k<=lim2;k++)
f[j][k]=(f[j][k]+g[now][j][k])%mod;
}
printf("%d",f[m][K]);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: