zoukankan      html  css  js  c++  java
  • 子串 NOIP2015 D2T2 luoguP2679 字符串处理+DP

    AC通道!

     题目大意:

    给定两个长度分别为 n 和 m 的字符串 A 和 B,选取 A 中的 k 个子串,使这 k 个子串按照先后顺序连接起来后等于 B 子串。

     

    输入输出样例

    输入 #1
    6 3 1
    aabaab
    aab
    输出 #1
    2
     
    输入 #2
    6 3 2 
    abaab 
    aab
    输出 #2
    7
     
    输入 #3
    6 6 3
    aabaab
    aab
    输出 #3
    7
     

    首先,看题目的要求。对于这类题目要求,以及如此之小的数据范围,考虑使用动态规划。

    /*------------------------加一段解释一下为什么要设0 / 1这一维---------------------------------------*/

    首先定义状态f[i][j][k]代表A里前i个字符挑出k个子串组成b的前j个字符的总方案数,那答案就是f[n][m][k];

    然后想怎么转移

    1.a[i] == b[j]

    f[i][j][k] = f[i-1][j-1][k-1]  +  f[i-1][j-1][k] + f[i-1][j][k]

    考虑a[i]可以自己一个人组成子串,跟前面的A[i-1]相连组成子串和不选A[i]

    2.a[i] != b[j]

    f[i][j][k] = f[i-1][j][k] (那就是不选A[i])

    但是,实际上, 在第一种情况中,dp[i-1][j-1][k]这样的表达是错误的。

    因为这种情况要求A[i-1]必须被选中,但f[i-1][j-1][k]指的是从A的前i-1个字符中挑出k个子串组成B的前j-1个字符,并没有规定一定要选A[i-1]。所以想到要再

    多加一个状态0/1表示选不选A[i]

    设计状态(需要记录什么?):

    1、A串匹配到哪里

    2、B串匹配到哪里

    3、当前已经用了多少子配串(k)

    4、上一位和这一位选还是不选(会影响到k,于是必须记录)

    于是,设计状态 f[i][j][p][0/1], 来表示A串匹配到 i 位, B串匹配到 j 位, 已经使用了 p 个子串,这一位选/不选的最大方案数。

    然后想状态方程:

    如果啊    a[i] == b[j] 

    那么有  f[i][j][p][0] = f[i - 1][j][p][0] + f[i - 1][j][p][1] ;  (即为上一位选和不选之和)

    f[i][j][k][1] = f[i-1][j-1][k][1](跟上一个连成一串) +  f[i-1][j-1][k-1][1](小团体,上一个用) +  f[i-1][j-1][k-1][0](小团体,上一个不用)

    如果不相等,

    不选的情况和上面一样:   f[i][j][p][0] = f[i - 1][j][p][0] + f[i - 1][j][p][1] ; 

    对于选择的情况,两个不一样,肯定不能选 所以 f[i][j][p][1] = 0;

    如此开数组,内存有点吃不消。(起码比赛的时候不敢开到8 * 107的int数组。

    观察一下状态方程,发现我们的 i  这一维, 永远都是i - 1, 也就是说,之前用过的有很大程度上是浪费的。

    于是我们用 ^ 操作让这一维滚动起来。

    千少万少,代码不能少

    #include <bits/stdc++.h> 
    #define N 1010
    #define M 210
    #define isdigit(c) ((c)>='0'&&(c)<='9')
    const int mod = (int)(1e9)+7;
    using namespace std;
    
    int f[2][M][M][2];
    char a[N],b[M];
    int n, m, k;
    bool flag = 1;
    
    inline int read(){
        int x = 0, s = 1;
        char c = getchar();
        while(!isdigit(c)){
            if(c == '-') s = -1;
            c = getchar();
        }
        while(isdigit(c)){
            x = (x << 1) + (x << 3) + (c ^ '0');
            c = getchar();
        }
        return x * s;
    }
    
    int main(){
        n = read(), m = read(), k = read();
        scanf("%s%s",a + 1, b + 1); /*一定要从第一位开始,而不能从0开始,不然之后会造成数组越界*/ 
        f[0][0][0][0] = f[1][0][0][0] = 1;
        for(int i = 1;i <= n; i++, flag ^= 1){
            for(int j = 1;j <= m; j++){
                for(int p = 1;p <= k; p++){
                    if(a[i] == b[j]){
                        f[flag][j][p][0] = (f[flag^1][j][p][0] % mod + f[flag^1][j][p][1] % mod) % mod;
                        f[flag][j][p][1] = (f[flag^1][j-1][p][1] % mod + (f[flag^1][j-1][p-1][0] + f[flag^1][j-1][p-1][1]) % mod) % mod;
                    }
                    else{
                        f[flag][j][p][0] = ((f[flag^1][j][p][0] + f[flag^1][j][p][1]) % mod);
                        f[flag][j][p][1] = 0;
                    }
                }
            }
        }
        printf("%d
    ",(f[n&1][m][k][0] + f[n&1][m][k][1]) % mod);/*用n的奇偶来判断滚动维度最后是 1 还是 0*/
        return 0;
    }
  • 相关阅读:
    Ftp、Ftps与Sftp之间的区别
    Previous Workflow Versions in Nintex Workflow
    Span<T>
    .NET Core 2.0及.NET Standard 2.0 Description
    Announcing Windows Template Studio in UWP
    安装.Net Standard 2.0, Impressive
    SQL 给视图赋权限
    Visual Studio for Mac中的ASP.NET Core
    How the Microsoft Bot Framework Changed Where My Friends and I Eat: Part 1
    用于Azure功能的Visual Studio 2017工具
  • 原文地址:https://www.cnblogs.com/wondering-world/p/12770909.html
Copyright © 2011-2022 走看看