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

    题面

    link

    题解

    noip快到了,所以来刷点历年真题。

    这道题经典的字符串匹配模型。

    我们还是按照套路设 \(f[i][j][k]\) 表示 从A串的前 \(i\) 位中,取出 \(k\) 个字符串,且B串匹配到第 \(j\) 位的方案数。

    可是你会发现你这样有可能会少算,因为与B串第 \(j\) 位相同的字母,他可以放也可以不放,这是两种情况。

    因此,我们在添加一维 \(f[i][j][k][0/1]\) 表示 从A串的前 \(i\) 位中,取出 \(k\) 个字符串,且B串匹配到第 \(j\) 位,且A串第 \(i\) 个字符在第 \(k\) 个字符串的的方案数

    初始化 \(f[i][0][0] = 1\) 因为从他这才开始与B串开始匹配,也是一种情况。

    转移:
    1. a[i] != b[j] 这时候A串第 \(i\) 位,我们是不可以选他的,因为他与B串不匹配了,即使我们后面再怎么算,也不会使 A串与B串相等
    f[i][j][k][0] = (f[i-1][j][k][0] + f[i-1][j][k][1])%p;//他的前一位可以选也可以不选
    f[i][j][k][1] = 0;//他这一位的字符一定不会被选,因为我们选了这个字符,后面再怎么选,也不会与B串相等
    
    1. a[i] == b[j] 他这一位与 B串第 \(j\) 位相等,但我们可以选他也可以不选。

      不选的情况就和不相等的情况一样,相等的话讨论是与前面的字符共同在一个串还是自己在新开一个串就行了。

    f[i][j][k][0] = (f[i-1][j][k][0] + f[i-1][j][k][1])%p;//和不相等的情况一样
    f[i][j][k][1] = ((f[i-1][j-1][k][1] + f[i-1][j-1][k-1][0]) % p + f[i-1][j-1][k-1][1])%p;
    
    

    最后的答案就是 f[n][m][k][0] + f[n][m][k][1]

    由于我们四维的数组开不下这么大,所以我们可以来滚动第一维(因为第一维只与 i-1 位有关)

    Code:

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    using namespace std;
    const int p = 1e9+7;
    int n,m,kk,ans,f[2][220][220][2];
    char a[1010],b[220];
    inline int read()
    {
        int s = 0,w = 1; char ch = getchar();
        while(ch < '0' || ch > '9'){if(ch == '-') w = -1; ch = getchar();}
        while(ch >= '0' && ch <= '9'){s = s * 10 + ch - '0'; ch = getchar();}
        return s * w;
    }
    int main()
    {
        n = read(); m = read(); kk = read();
        scanf("%s",a+1); scanf("%s",b+1);
        f[0][0][0][0] = 1;//初始化
        for(int i = 1, now = 1; i <= n; i++, now ^= 1)//滚动第一维
        {
        	f[now][0][0][0] = 1;
            for(int j = 1; j <= m; j++)
            {
                for(int k = 1; k <= kk; k++)
                {
                    if(a[i] != b[j]) //不相等的情况
    		{
    		      f[now][j][k][0] = (f[now ^ 1][j][k][0] + f[now ^ 1][j][k][1])%p;
    		      f[now][j][k][1] = 0;
    		}
                    if(a[i] == b[j])
                    {
                          f[now][j][k][0] = (f[now ^ 1][j][k][0] + f[now ^ 1][j][k][1])%p;
                          f[now][j][k][1] = ((f[now ^ 1][j-1][k][1] + f[now ^ 1][j-1][k-1][0]) % p + f[now ^ 1][j-1][k-1][1])%p;//他自己和前一个字符串在同一个集合的情况 f[now ^ 1][j-1][k][1]
                          //他自己新开一个集合,但前一个字符不在上一个集合的情况 f[now ^ 1][j-1][k-1][0], 在上一个集合的情况 f[now ^ 1][j-1][k-1][1]
                    }
                }
            }
        }
        ans = (f[n & 1][m][kk][0] + f[n & 1][m][kk][1])%p;
        printf("%d\n",ans);
        return 0;
    } 
    
  • 相关阅读:
    filter 在CSS用的效果
    Safari的CSS HACK方法
    HTML5网页如何让所有的浏览器都能识别语义元素标签样式
    Android/IOS APP界面设计之尺寸规范
    四、添加路由的两种方式
    三、配置
    二、注册登录状态维持(template和session)
    一、最小的Flask应用
    django之图形验证码生成
    django之环境配置
  • 原文地址:https://www.cnblogs.com/genshy/p/13592036.html
Copyright © 2011-2022 走看看