• 【洛谷2679】子串(动态规划)


    点此看题面

    大致题意: 让你从一个字符串中选择(k)个互不重叠的非空子串,使其按序拼接恰好组成另一个给定的字符串,求方案数。

    动态规划

    比较显然,这可以用动态规划解决。

    考虑用(f_{i,j,t,s})表示在第一个字符串前(i)位中选择(t)个子串组成第二个字符串前(j)位,且选/不选(1/0)第(i)的方案数,并用(g_{i,j,t})记录(f_{i,j,t,0}+f_{i,j,t,1})

    则不难得出(f_{i,j,t,0}=g_{i-1,j,t})

    而对于(f_{i,j,t,1})的转移,就需要分类讨论了:

    (s1_i!=s2_j),显然该位不能选,故(f_{i,j,t,1}=0)

    (s1_i==s2_j),则有两种情况:新选一个子串或不新选一个子串。即(f_{i,j,t,1}=f_{i-1,j-1,t,1}+g_{i-1,j-1,t-1})

    大致思路就是如此简单。

    关于内存

    等等,数组好像开不下?

    (hl666)奆佬说:“滚存不就好了吗!”

    于是这题就做完了。

    代码

    #include<bits/stdc++.h>
    #define N 1000
    #define M 200
    #define XRY 1000000007
    #define Inc(x,y) ((x+=(y))>=XRY&&(x-=XRY))
    using namespace std;
    inline int GetSum(int x,int y) {return Inc(x,y),x;}
    int n,m,k,f[2][M+5][M+5][2],g[2][M+5][M+5];char s1[N+5],s2[M+5];
    int main()
    {
    	register int i,j,t;
    	scanf("%d%d%d%s%s",&n,&m,&k,s1,s2),g[0][0][0]=g[1][0][0]=f[0][0][0][0]=f[1][0][0][0]=1;//读入+初始化
    	for(i=1;i<=n;++i) for(j=1;j<=m;++j) for(t=1;t<=k;++t)
    	{
    		f[i&1][j][t][0]=g[(i&1)^1][j][t],//转移f[i][j][t][0]
    		f[i&1][j][t][1]=s1[i-1]^s2[j-1]?0:GetSum(f[(i&1)^1][j-1][t][1],g[(i&1)^1][j-1][t-1]),//转移f[i][j][t][1]
    		g[i&1][j][t]=GetSum(f[i&1][j][t][0],f[i&1][j][t][1]);//计算g[i][j][t]
    	}
    	return printf("%d",g[n&1][m][k]),0;//输出答案
    } 
    
  • 相关阅读:
    MySQL 处理重复数据
    MySQL 序列使用
    MySQL 元数据
    MySQL 临时表和复制表
    MySQL 索引
    MySQL ALTER命令-修改数据表名或者修改数据表字段
    MySQL 事务
    MySQL 正则表达式
    MySQL NULL 值处理
    MySQL 排序
  • 原文地址:https://www.cnblogs.com/chenxiaoran666/p/Luogu2679.html
Copyright © 2020-2023  润新知