1. 程式人生 > >洛谷P2679 子串

洛谷P2679 子串

一個 需要 register 方程 line name .org lse algorithm

傳送門

分析:

首先發現,為了保證無後效性的一位一位往後推,我們需要記錄當前推到 $ a $ 串的哪一個位置了;接著還有記錄匹配了 $ b $ 串的那幾個字符。因為是按照原串順序,所以相當於是即匹配 $ b $ 串的前幾個字符。有這些還不夠,我們還要記錄劃分了幾個子串。最後,為了便於轉移,我們還要標記一維 $ 0/1 $ 狀態,表示 $ a $ 串中的第 $ i $ 個字符是否選入。

這樣,我們就設計好了狀態。我們記 $ f_{i,j,p,v} $ 表示到 $ a $ 串的第 $ i $ 個位置為止使用 $ p $ 個子串匹配 $ b $ 串前 $ j $ 位字符且第 $ i $ 個位置選或不選 $ (v) $ 的方案數。

我們分情況考慮:

$ 1. $ 當 $ a_i=b_j $ 時:

①$ f_{i,j,p,0} $ :由於這位不選,所以就是前面一位選和不選方案數之和,即 $ f_{i,j,p,0}=f_{i-1,j,p,0}+f_{i-1,j,p,1} $ 。

② $ f_{i,j,p,1}=f_{i-1,j-1,p,1}+f_{i-1,j-1,p-1,0}+f_{i-1,j-1,p-1,1} $ 。

$ 2 . $ 當 $ a_i\ne b_j $ 時:

①不選情況同上,即 $ f_{i,j,p,0}=f_{i-1,j,p,0}+f_{i-1,j,p,1} $ 。

②由於選不了,自然就是 $ 0 $ ,即 $ f_{i,j,p,1}=0 $ 。

觀察轉移方程,發現每次轉移只用到了前一位!於是我們把第一維很愉快地滾掉了。這樣,空間復雜度就保證是 $ O(mk) $ 了。那麽時間呢?時間是 $ O(n\cdot mk) $ ,但是時間不像空間,這個復雜度是可以接受的。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
#include <cmath>
#define re register
#define mod 1000000007
using namespace std ;
const int maxn = 1005 ;
const int maxm = 210 ; 

int n , m , k ;
char a[maxn] , b[maxm] ;
bool val = true ;
int f[2][maxm][maxm][2] ;
//f[i][j][p][v]:表示a串的第i個位置為止使用p個子串匹配b串的前j位字符且第i個位置選還是不選(v)的方案數
 
inline void dp() {
    f[0][0][0][0] = f[1][0][0][0] = 1 ;
    for(re int i = 1 ; i <= n ; ++ i , val ^= 1) 
        for(re int j = 1 ; j <= m ; ++ j) 
            for(re int p = 1 ; p <= k ; ++ p) {
                if(a[i] == b[j]) {
                    f[val][j][p][0] = (f[val ^ 1][j][p][0] + f[val ^ 1][j][p][1]) % mod ;
                    f[val][j][p][1] = (f[val ^ 1][j - 1][p][1] + (f[val ^ 1][j - 1][p - 1][0] + f[val ^ 1][j - 1][p - 1][1]) % mod) % mod ;
                }
                else {
                    f[val][j][p][0] = (f[val ^ 1][j][p][0] + f[val ^ 1][j][p][1]) % mod ;
                    f[val][j][p][1] = 0 ;
                }
            }
}

int main () {
    scanf("%d%d%d" , &n , &m , &k) ;
    scanf("%s%s" , a + 1 , b + 1) ;
    dp() ;
    printf("%d\n" , (f[n & 1][m][k][0] + f[n & 1][m][k][1]) % mod) ;
    return 0 ;
}

洛谷P2679 子串