zoukankan      html  css  js  c++  java
  • P2679 子串

    题目描述

    有两个仅包含小写英文字母的字符串 AA 和 BB 。

    现在要从字符串 AA 中取出 kk 个互不重叠的非空子串,然后把这 kk 个子串按照其在字符串 AA 中出现的顺序依次连接起来得到一个新的字符串。请问有多少种方案可以使得这个新串与字符串 BB 相等?

    注意:子串取出的位置不同也认为是不同的方案。

    输入输出格式

    输入格式:

     

    第一行是三个正整数 n,m,kn,m,k ,分别表示字符串 AA 的长度,字符串 BB 的长度,以及问题描述中所提到的 kk ,每两个整数之间用一个空格隔开。

    第二行包含一个长度为 nn 的字符串,表示字符串 AA 。

    第三行包含一个长度为 mm 的字符串,表示字符串 BB 。

     

    输出格式:

     

    一个整数,表示所求方案数。

    由于答案可能很大,所以这里要求输出答案对 10000000071000000007 取模的结果。

     

    输入输出样例

    输入样例#1: 
    6 3 1 
    aabaab 
    aab
    输出样例#1: 
    2
    输入样例#2: 
    6 3 2 
    aabaab 
    aab
    输出样例#2: 
    7
    输入样例#3: 
    6 3 3 
    aabaab 
    aab
    输出样例#3: 
    7

    说明

    对于第 1 组数据: 1≤n≤500,1≤m≤50,k=11n500,1m50,k=1 ;
    对于第 2 组至第 3 组数据: 1≤n≤500,1≤m≤50,k=21n500,1m50,k=2 ;
    对于第 4 组至第 5 组数据: 1≤n≤500,1≤m≤50,k=m1n500,1m50,k=m ;
    对于第 1 组至第 7 组数据: 1≤n≤500,1≤m≤50,1≤k≤m1n500,1m50,1km ;
    对于第 1 组至第 9 组数据: 1≤n≤1000,1≤m≤100,1≤k≤m1n1000,1m100,1km ;
    对于所有 10 组数据: 1≤n≤1000,1≤m≤200,1≤k≤m1n1000,1m200,1km 。

    Solution:

      注意选的子串是按顺序连接,每个位置要么选要么不选,很显然的满足最优子结构,而一般字符串DP都是直接定义状态$f[i][j]$表示匹配到$a$串的第$i$位和$b$串的第$j$位的某个值。

      本题由于多了个限制只能选$k$个子串,我们可以先尝试这样去定义状态,$f[i][j][k]$第三维表示当前状态选了多少个子串,但是很显然转移时无法考虑当前第$i$位究竟选还是不选,于是我们再多加一维,用$f[i][j][k][p]$第四维表示当前第$i$个字符选还是不选。

      那么不难得到状态转移方程:

        当$a_i=b_j$时,$f[i][j][k][0]=f[i-1][j][k][0]+f[i-1][j][k][1],f[i][j][k][1]=f[i-1][j-1][k-1][1]+f[i-1][j-1][k-1][0]+f[i][j-1][k][1]$

        当$a_i eq b_j$时,$f[i][j][k][0]=f[i-1][j][k][0]+f[i-1][j][k][1],f[i][j][k][1]=0$

      然后存在一个问题就是直接这样定义状态会爆空间,而我们发现状态第一维每次都是从上一次转移,于是果断滚掉就好了。

    代码:

    #include<bits/stdc++.h>
    #define il inline
    #define ll long long
    #define For(i,a,b) for(int (i)=(a);(i)<=(b);(i)++)
    #define Bor(i,a,b) for(int (i)=(b);(i)>=(a);(i)--)
    using namespace std;
    const int mod=1e9+7,M=1005;
    int n,m,k,f[2][M/5][M/5][2],t;
    char a[M],b[M];
    
    int main(){
        scanf("%d%d%d",&n,&m,&k);
        scanf("%s%s",a+1,b+1);
        f[0][0][0][0]=f[1][0][0][0]=1;
        For(i,1,n) {
            For(j,1,m) For(p,1,k)
            if(a[i]==b[j])
                f[t^1][j][p][0]=(f[t][j][p][0]+f[t][j][p][1])%mod,
                f[t^1][j][p][1]=((f[t][j-1][p][1]+f[t][j-1][p-1][1])%mod+f[t][j-1][p-1][0])%mod;
            else
                f[t^1][j][p][0]=(f[t][j][p][0]+f[t][j][p][1])%mod,
                f[t^1][j][p][1]=0;
            t^=1;
        }
        cout<<(f[t][m][k][0]+f[t][m][k][1])%mod;
        return 0;
    }
  • 相关阅读:
    centos8 将SSSD配置为使用LDAP并要求TLS身份验证
    Centos8 搭建 kafka2.8 .net5 简单使用kafka
    .net core 3.1 ActionFilter 拦截器 偶然 OnActionExecuting 中HttpContext.Session.Id 为空字符串 的问题
    Springboot根据不同环境加载对应的配置
    VMware Workstation12 安装 Centos8.3
    .net core json配置文件小结
    springboot mybatisplus createtime和updatetime自动填充
    .net core autofac依赖注入简洁版
    .Net Core 使用 redis 存储 session
    .Net Core 接入 RocketMQ
  • 原文地址:https://www.cnblogs.com/five20/p/9362251.html
Copyright © 2011-2022 走看看