zoukankan      html  css  js  c++  java
  • 2015D2T2 子串

    2015D2T2 子串

    problem

    给定两个小写英文字母串(A,B),从(A)中取出(k)个子串按照先后顺序连接得到新的字符串。求可以使新串和(B)相等的方案数。答案对(10^9+7)取模。

    solution

    (f(i,j,k))表示A串前i个字符里,使用了k个子串,来匹配了B串前j个字符。
    可列出方程(f(i,j,k)=f(i-1,j-1,k-1)+f(i-1,j-1,k)),即为A串前i个字符里,使用了k个子串,匹配了B串前j个字符的方案数,等价于单独使用第i-1个字符作为一个子串的方案数和不单独使用的方案数
    但是我们要考虑到使用和不使用,这个就涉及到0/1的这一维。所以我们添加0/1维,来表示使用了当前字符和没使用当前的字符。

    转移方程

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

    如果第i位不使用
    第i-1位未使用时,前i-1位匹配前j位使用k个子串
    第i-1位使用时,前i-1位匹配前j位使用k个子串

    [[a_i=b_j]f(i,j,k,1)=f(i-1,j-1,k-1,0)+f(i-1,j-1,k,1)+f(i-1,k-1,k-1,1) ]

    如果第i位使用,即a[i]==b[j]

    1. 第i-1位未使用而第i位作为一个新子串
    2. 第i位和前面连在一起,不单独使用
    3. 第i-1位使用了,但第i位仍作为一个新子串。

    边界条件

    对于A子串前i位,匹配B串第1个字符,那么只可能使用1个字符串,这种情况如果第i位不进行匹配,那么方案数就是之前所有能与第1位匹配的字符,所以

    [f(i,1,1,0)=sumlimits_{i=1}^{n-1}[a_i=b_1] ]

    同上,但如果B串第一位和A串第一位匹配了话,那么

    [f[i][1][1][1]=1 ]

    是显然的。

    总结

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

    [[a_i=b_j]f(i,j,k,1)=f(i-1,j-1,k-1,0)+f(i-1,j-1,k,1)+f(i-1,k-1,k-1,1) ]

    [f(i,1,1,0)=sumlimits_{i=1}^{n-1}[a_i=b_1] ]

    [f[i][1][1][1]=1 ]

    维度优化

    方程里只有i和i-1被来回调用,其余例如i-2,i-3在接下来的动态规划里是不需要的,可以把数组滚动起来。设置一个t1,t2变量分别是0,1,来回变换。最后交换的时候记得清零。

    code

    #include <cstdio>
    #include <algorithm>
    #include <cmath>
    #include <cstring>
    #include <iostream>
    #include <queue>
    using namespace std;
    long long read(){
    	int a=0,op=1;char c=getchar();
    	while(c>'9'||c<'0') {if(c=='-') op=-1;c=getchar();}
    	while(c>='0'&&c<='9'){a*=10,a+=c^48,c=getchar();}
    	return a*op;
    }
    const int maxn=1005;
    const int mod=1e9+7;
    char a[maxn],b[maxn];
    long long n,m,k;
    long long dp[2][201][201][2],s,t1,t2=1;
    int main(){
    	n=read(),m=read(),k=read();
    	scanf("%s%s",a+1,b+1);
    	for(int i=1;i<=n;i++){
    		swap(t1,t2);
    		dp[t1][1][1][0]=s;
    		if(a[i]==b[1]) dp[t1][1][1][1]=1,s++;
    		for(int j=2;j<=m;j++){
    			for(int u=1;u<=k;u++){
    				if(a[i]==b[j]) dp[t1][j][u][1]=((dp[t2][j-1][u-1][1]+dp[t2][j-1][u][1])%mod+dp[t2][j-1][u-1][0])%mod;
    				dp[t1][j][u][0]=(dp[t2][j][u][0]+dp[t2][j][u][1])%mod;
    			}
    		}
    		for(int j=1;j<=m;j++) for(int u=1;u<=k;u++) dp[t2][j][u][1]=dp[t2][j][u][0]=0;
    	}
    	printf("%lld",(dp[t1][m][k][1]+dp[t1][m][k][0])%mod);
    	return 0;
    }
    
  • 相关阅读:
    解决ASP.NET MVC AllowAnonymous属性无效导致无法匿名访问控制器的问题
    ASP.NET MVC 4 RC的JS/CSS打包压缩功能 (转载)
    oracle报错ORA-01507
    oracle 大表删除数据后,回收空间的问题。
    解决MySQL服务启动时报1067错误
    尚未在 Web 服务器上注册 ASP.NET 4.0” 的解决办法
    thymeleaf中相对路径的两种方式
    史上最详 Thymeleaf 使用教程
    isNotBlank()和isNotEmpty()总结
    IDEA去除掉虚线,波浪线,和下划线实线的方法
  • 原文地址:https://www.cnblogs.com/liuziwen0224/p/2015d2t2.html
Copyright © 2011-2022 走看看