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

    传送门

    这道题能看出来是DP。其实这个的状态还是比较好确定的,因为首先我们要从A串中选出一些非空不相交子串,而且他们还必须能按原来的顺序拼成B串,那么我们就知道在枚举到A串第i位,B串第j位的时候,A串前i位中选出的子串肯定是能匹配成B串前j位的。

    于是乎我们就有了状态:dp[i][j][k]表示枚举A串到第i位,枚举B串到第j位,已经在A串中选择了k个子串的方案数。这样我们发现还不够,于是又加上一维0/1,表示当前第i位的字符是否选择。(听起来这个和NOIP2016换教室的DP状态有点相似)

    之后我就发现自己把状态编出来之后不知道怎么转移……QAQ

    这种时候一般怎么考虑?首先因为这个要考虑到两个字符串之间的匹配问题,所以当然是分两种状况,第一种是枚举到的两个字符能匹配,之后再分别转移当前这一位取或者不取,得到如下方程:

    dp[i][j][k][0] = dp[i-1][j][k][0] + dp[i-1][j][k][1];

    dp[i][j][k][1] = dp[i-1][j-1][k][1] + dp[i-1][j-1][k-1][0] + dp[i-1][j-1][k-1][1];

    上面一行还是比较好想的,至于下面一行,我们考虑到当前状态可以是与上一位在同一个被选取的子串中(k不变),这种情况下上一位必须是被选择的,之后再考虑不在同一个子串中的情况即可。

    第二种就是枚举的两个字符不匹配,这个就比较好得到如下方程:

    dp[i][j][k][0] = dp[i-1][j][k][0] + dp[i-1][j][k][1];

    dp[i][j][k][1] = 0;

    上面那一行,因为你这一位反正也不取,所以其实是同上的。然后下面这一行因为这一个字符不可取,所以结果为0.

    这样我们把过程弄完之后,发现时间复杂度是O(2nmk),这个能过,但是空间复杂度就不行了。但是因为每一位只会用到前一位的状态,所以我们可以直接把第一维滚动掉即可。(这样好像只要2M左右空间就能过了)

    初始条件是dp[0][0][0][0] = dp[1][0][0][0] = 1;

    好DP题呀……看一下代码。

    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<iostream>
    #include<cmath>
    #include<queue>
    #include<set>
    #define rep(i,a,n) for(int i = a;i <= n;i++)
    #define per(i,n,a) for(int i = n;i >= a;i--)
    #define enter putchar('
    ')
    
    using namespace std;
    typedef long long ll;
    const int M = 50005;
    const int mod = 1000000007;
    
    int read()
    {
        int ans = 0,op = 1;
        char ch = getchar();
        while(ch < '0' || ch > '9')
        {
        if(ch == '-') op = -1;
        ch = getchar();
        }
        while(ch >= '0' && ch <= '9')
        {
        ans *= 10;
        ans += ch - '0';
        ch = getchar();
        }
        return ans * op;
    }
    
    int n,m,k;
    ll dp[2][205][205][2];
    char a[1005],b[205];
    
    int main()
    {
        n = read(),m = read(),k = read();
        scanf("%s",a+1);
        scanf("%s",b+1);
        dp[0][0][0][0] = dp[1][0][0][0] = 1;
        rep(i,1,n)
        rep(j,1,m)
        rep(p,1,k)
        {
        int g = i&1;
             if(a[i] == b[j])
        {
            dp[g][j][p][0] = dp[g^1][j][p][0] + dp[g^1][j][p][1];
            dp[g][j][p][0] %= mod;
            dp[g][j][p][1] = dp[g^1][j-1][p][1] + dp[g^1][j-1][p-1][0] + dp[g^1][j-1][p-1][1];
            dp[g][j][p][1] %= mod;
        }
        else if(a[i] != b[j])
        {
            dp[g][j][p][0] = dp[g^1][j][p][0] + dp[g^1][j][p][1];
            dp[g][j][p][0] %= mod;
            dp[g][j][p][1] = 0;
        }
        }
        printf("%lld
    ",(dp[n&1][m][k][0] + dp[n&1][m][k][1]) % mod);
        return 0;
    }
  • 相关阅读:
    洛谷p1017 进制转换(2000noip提高组)
    Personal Training of RDC
    XVIII Open Cup named after E.V. Pankratiev. Grand Prix of Eurasia
    XVIII Open Cup named after E.V. Pankratiev. Grand Prix of Peterhof.
    Asia Hong Kong Regional Contest 2019
    XVIII Open Cup named after E.V. Pankratiev. Grand Prix of Siberia
    XVIII Open Cup named after E.V. Pankratiev. Ukrainian Grand Prix.
    XVIII Open Cup named after E.V. Pankratiev. GP of SPb
    卜题仓库
    2014 ACM-ICPC Vietnam National First Round
  • 原文地址:https://www.cnblogs.com/captain1/p/9716506.html
Copyright © 2011-2022 走看看