[luogu-2679]noip2015day2-T2 子串 题解

来源:互联网 发布:画结构式的软件 编辑:程序博客网 时间:2024/05/18 05:05

题目传送门
题意解析:题目给了两个字符串A和B,求由m个A的子串连接起来成为B的方案数是多少。


My opinion:看到这题目的时候想到了最长公共子串,dp嘛。我一开始想到了一个三维状态,dp[i][j][k]表示A的匹配到第i个字符,B匹配到第j个字符,一共是k个子串的方案数,但是这样子做还需要多一重循环来枚举,明显超时。所以为了防TLE,使用了万金油——加维,dp[i][j][k][0/1]中的[0/1]来表示这个字符是否属于同一个子串。然而后来我写不出来(有dalao告诉我这样可以,但是我就是菜到写不出来),所以为了去掉那一维,我采取了用s[i][j][k]来记录答案的前缀和(并且将i和j的状态换了一下),这样就可以省去一重枚举了。
总结:
1、输入
2、dp
方程为
方程为


奇怪的代码:

#include<iostream>#include<cmath>#include<cstdio>#include<cstring>#include<algorithm>#define rep(i,a,n) for (int i=a;i<=n;i++)#define per(i,a,n) for (int i=a;i>=n;i--)#define Clear(a,x) memset(a,x,sizeof(a))#define ll long long#define INF 2000000000#define eps 1e-8using namespace std;int read(){    int x=0,f=1;    char ch=getchar();    while (ch<'0'||ch>'9') f=ch=='-'?-1:f,ch=getchar();    while (ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();    return x*f;}const int maxn=1005,maxm=205,mod=1000000007;char A[maxn],B[maxm];int f[2][maxn][maxm],s[2][maxn][maxn];int n,m,K;int main(){    n=read(),m=read(),K=read();    scanf("%s",A+1);    scanf("%s",B+1);    rep(j,0,n)        s[0][j][0]=1;    A[0]=' ',B[0]=' ';    rep(i,1,m){        int now=i%2,last=(i-1)%2;        Clear(f[now],0);        Clear(s[now],0);        rep(j,1,n)            rep(k,1,K)                if (A[j]==B[i]){                    if (A[j-1]==B[i-1]||i==1)                        f[now][j][k]+=f[last][j-1][k],f[now][j][k]%=mod;                    f[now][j][k]+=s[last][j-1][k-1],f[now][j][k]%=mod;                    s[now][j][k]+=s[now][j-1][k]+f[now][j][k],s[now][j][k]%=mod;                }else s[now][j][k]+=s[now][j-1][k]+f[now][j][k],s[now][j][k]%=mod;    }    printf("%d\n",s[m%2][n][K]);    return 0;}