洛谷 P2679 子串 解題報告
阿新 • • 發佈:2018-06-10
span 出現 但是 math 題目 HA 現在 ons clas 的字符串,表示字符串\(B\)。
\(dp[l][i][j][0]=dp[l][i-1][j][0]+dp[l][i-1][j][1]\)
P2679 子串
題目描述
有兩個僅包含小寫英文字母的字符串\(A\)和\(B\)。
現在要從字符串\(A\)中取出\(k\)個互不重疊的非空子串,然後把這\(k\)個子串按照其在字符串\(A\)中出現的順序依次連接起來得到一個新的字符串。請問有多少種方案可以使得這個新串與字符串\(B\)相等?
註意:子串取出的位置不同也認為是不同的方案。
輸入輸出格式
輸入格式:
第一行是三個正整數\(n,m,k\) ,分別表示字符串\(A\)的長度,字符串\(B\)的長度,以及問題描述中所提到的\(k\) ,每兩個整數之間用一個空格隔開。
第二行包含一個長度為\(n\)的字符串,表示字符串\(A\) 。
第三行包含一個長度為\(m\)
輸出格式:
一個整數,表示所求方案數。
由於答案可能很大,所以這裏要求輸出答案對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 子串 解題報告