zoukankan      html  css  js  c++  java
  • NOIP2015提高组 子串

    题目链接:https://ac.nowcoder.com/acm/problem/16463

    题目描述

        有两个仅包含小写英文字母的字符串 A 和 B。现在要从字符串 A 中取出 k 个互不重叠的非空子串,然后把这 k 个子串按照其在字符串 A 中出现的顺序依次连接起来得到一个新的字符串,请问有多少种方案可以使得这个新串与字符串 B 相等?注意:子串取出的位置不同也认为是不同的方案。

    输入描述:

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

    输出描述:

    输出共一行,包含一个整数,表示所求方案数。由于答案可能很大,所以这里要求输出答案对 1,000,000,007 取模的结果。

    示例1

    输入

    复制
    6 3 1
    aabaab
    aab

    输出

    复制
    2

    说明

    样例 1所有合法方案如下:(加下划线的部分表示取出的子串)

    aab aab / aab aab
    示例2

    输入

    复制
    6 3 2
    aabaab
    aab

    输出

    复制
    7

    说明

    样例 2:所有合法方案如下:(加下划线的部分表示取出的子串)
    a ab aab / aba ab / a ba ab / aab a ab
    aa b aab/ aa baa / aab aa b
    示例3

    输入

    复制
    6 3 3
    aabaab
    aab

    输出

    复制
    7

    说明

    样例 3所有合法方案如下:(加下划线的部分表示取出的子串)
    a a b aab / a a baa / ab a / aba a b
    a b a /a ba a b / aab a a b

    备注:

    对于第 1 组数据:1≤n≤500,1≤m≤50,k=1;
    对于第 2 组至第 3 组数据:1≤n≤500,1≤m≤50,k=2;
    对于第 4 组至第 5 组数据:1≤n≤500,1≤m≤50,k=m;
    对于第 1 组至第 7 组数据:1≤n≤500,1≤m≤50,1≤k≤m;
    对于第 1 组至第 9 组数据:1≤n≤1000,1≤m≤100,1≤k≤m;
    对于所有 10 组数据:1≤n≤1000,1≤m≤200,1≤k≤m。


    解题思路:设状态dp【i】【j】【k】字符串ch前i个组成字符串ch1前j个分成k段的方案数
    那么状态转移方程为:
    if(ch【i】==ch1【j】)那么dp【i】【j】【k】=dp【i-1】【j-1】【k-1】(即在原基础上加上字符ch【i】,ch【i】为新的一段)
    if(ch【i】==ch1【j】&&ch【i-1】==ch1【j-1】)那么dp【i】【j】【k】=dp【i-1】【j-1】【k-1】+dp【i-1】【j-1】【k】-dp【i-2】【j-1】【k】(此时ch【i】可以直接加在最末尾,而不构成新的一段)。这里解释一下
    为什么后面还要减去dp【i-2】【j-1】【k】吧。要把ch【i】添加到最末的前提是字符ch【i-1】存在,而dp【i-1】【j-1】【k】这个状态还包含ch【i-1】不存在的情况,所以必须减去ch【i-1】不存在的方案数。
    初始状态就设dp【i】【0】【0】=1就好了,还有值得注意的是,这个道题需要用滚动数组,不然会超内存。
    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int mod=1e9+7;
    const int maxn=1005;
    int dp[3][205][205];
    char ch[maxn],ch1[maxn];
    int main(){
        int l1,l2,k;
        string st1,st2;
        scanf("%d%d%d",&l1,&l2,&k);
    	scanf("%s%s",ch+1,ch1+1);
        int ans=0;
        dp[0][0][0]=1;
        for(int i=1;i<=l1;i++){
        	dp[i%3][0][0]=1;
        	for(int j=1;j<=l2;j++){
        		for(int m=1;m<=k;m++){
        			dp[i%3][j][m]=dp[(i-1)%3][j][m];
        			if(ch[i]==ch1[j]){
        				dp[i%3][j][m]=(dp[i%3][j][m]+dp[(i-1)%3][j-1][m-1])%mod;
        				if(ch[i-1]==ch1[j-1]){
        					dp[i%3][j][m]=((dp[i%3][j][m]+dp[(i-1)%3][j-1][m])%mod-(i>=2?dp[(i-2)%3][j-1][m]:0)+mod)%mod;
    					}
    				}	
    			}
    		}
    	}
        printf("%d
    ",dp[l1%3][l2][k]);
        return 0;
    }
    

      

  • 相关阅读:
    LeetCode 227. Basic Calculator II
    LeetCode 224. Basic Calculator
    LeetCode 103. Binary Tree Zigzag Level Order Traversal
    LeetCode 102. Binary Tree Level Order Traversal
    LeetCode 106. Construct Binary Tree from Inorder and Postorder Traversal
    LeetCode 105. Construct Binary Tree from Preorder and Inorder Traversal
    LeetCode 169. Majority Element
    LeetCode 145. Binary Tree Postorder Traversal
    LeetCode 94. Binary Tree Inorder Traversal
    LeetCode 144. Binary Tree Preorder Traversal
  • 原文地址:https://www.cnblogs.com/Zhi-71/p/11278626.html
Copyright © 2011-2022 走看看