1. 程式人生 > >洛谷 P2679 子串 解題報告

洛谷 P2679 子串 解題報告

span 出現 但是 math 題目 HA 現在 ons clas

P2679 子串

題目描述

有兩個僅包含小寫英文字母的字符串\(A\)\(B\)

現在要從字符串\(A\)中取出\(k\)個互不重疊的非空子串,然後把這\(k\)個子串按照其在字符串\(A\)中出現的順序依次連接起來得到一個新的字符串。請問有多少種方案可以使得這個新串與字符串\(B\)相等?

註意:子串取出的位置不同也認為是不同的方案。

輸入輸出格式

輸入格式:

第一行是三個正整數\(n,m,k\) ,分別表示字符串\(A\)的長度,字符串\(B\)的長度,以及問題描述中所提到的\(k\) ,每兩個整數之間用一個空格隔開。

第二行包含一個長度為\(n\)的字符串,表示字符串\(A\)

第三行包含一個長度為\(m\)

的字符串,表示字符串\(B\)

輸出格式:

一個整數,表示所求方案數。

由於答案可能很大,所以這裏要求輸出答案對1000000007取模的結果。

說明:

對於所有 10 組數據: \(1≤n≤1000,1≤m≤200,1≤k≤m\)


這題好難想orz,,,

令dp[l][i][j][0/1]代表匹配到第\(l\)段時,A串匹配到第\(i\)段,B串匹配到第\(j\)段,A串的第\(i\)位是否處於匹配。

關於第四維的設計,我們由 B串必須完整匹配,而A串不需要完整匹配 推出

轉移:
\(dp[l][i][j][1]=dp[l-1][i-1][j-1][1]+dp[l-1][i-1][j-1][0]+dp[l][i-1][j-1][1],a[i]==b[j]\)


\(dp[l][i][j][0]=dp[l][i-1][j][0]+dp[l][i-1][j][1]\)

這樣空間肯定炸了的,我們考慮用滾動數組優化。

但是滾動數組優化的話,我們得稍稍處理一下\(a[i]!=b[j]\)\(dp[l][i][j][1]\)的值為0,還有起始邊界的置0,否則循環用會出問題。

一個細節,加三項時每兩項都得膜,否則只有40分好像。。


code:

#include <cstdio>
const int N=1010;
const int M=203;
const int mod=1000000007;
char c1[N],c2[M];
int n,m,k,dp[2][N][M][2];
int main()
{
    scanf("%d%d%d",&n,&m,&k);
    scanf("%s%s",c1+1,c2+1);
    for(int i=0;i<=n;i++)
        dp[0][i][0][0]=1;
    for(int l=1;l<=k;l++)
    {
        for(int i=1;i<=n;i++)
            for(int j=1;j<=i;j++)
            {
                if(c1[i]==c2[j])
                    dp[l&1][i][j][1]=((dp[(l-1)&1][i-1][j-1][1]+dp[(l-1)&1][i-1][j-1][0])%mod+dp[l&1][i-1][j-1][1])%mod;
                else 
                    dp[l&1][i][j][1]=0;
                dp[l&1][i][j][0]=(dp[l&1][i-1][j][0]+dp[l&1][i-1][j][1])%mod;
            }
        if(l==2)
            for(int i=0;i<=n;i++)
                dp[0][i][0][0]=0;
    }
    printf("%d\n",(dp[k&1][n][m][0]+dp[k&1][n][m][1])%mod);
}

2018.6.10

洛谷 P2679 子串 解題報告