[NOIP2015提高组]子串 DP

来源:互联网 发布:十大经典排序算法 编辑:程序博客网 时间:2024/06/06 01:57

题目描述

有两个仅包含小写英文字母的字符串 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]);}
原创粉丝点击