1. 程式人生 > >Vijos[1982]NOIP2015Day2T2 子串 substring 動態規劃

Vijos[1982]NOIP2015Day2T2 子串 substring 動態規劃

bsp 得到 mat main tar cstring font () 鏈接

子串 (substring.cpp/c/pas)   題目鏈接

【問題描述】
有兩個僅包含小寫英文字母的字符串 A 和 B。現在要從字符串 A 中取出 k 個 互不重疊 的非空子串,然後把這 k 個子串按照其在字符串 A 中出現的順序依次連接起來得到一
個新的字符串,請問有多少種方案可以使得這個新串與字符串 B 相等?註意:子串取出的位置不同也認為是不同的方案 。
【輸入格式】
輸入文件名為 substring.in。
第一行是三個正整數 n,m,k,分別表示字符串 A 的長度,字符串 B 的長度,以及問題描述中所提到的 k,每兩個整數之間用一個空格隔開。
第二行包含一個長度為 n 的字符串,表示字符串 A。


第三行包含一個長度為 m 的字符串,表示字符串 B。
【輸出格式】
輸出文件名為 substring.out。
輸出共一行,包含一個整數,表示所求方案數。 由於答案可能很大,所以這裏要求對輸出答案對 1,000,000,007 取模 的結果。
【輸入輸出樣例 1】
substring.in
6 3 1
aabaab
aab
substring.out
2
【輸入輸出樣例 2】
substring.in
6 3 2
aabaab
aab
substring.out
7
【輸入輸出樣例 3】
substring.in
6 3 3
aabaab
aab
substring.out
7

【題解】
NOIP2015Day2T2
一道好好的DP題
我們用dp[i][j][k]表示在B串中匹配i個,在A串中匹配到的位置為j,共使用k個子串的方案總數,則dp[i][j][k]=Σdp[i-1][j‘][k-1] +dp[i-1][j-1][k]


那麽,對於Σ可以用前綴和優化,這樣的時間就可以卡進去了,但是空間還是要炸,所以我們采用滾動數組來優化空間即可。詳見代碼。

#include <cstring>
#include <algorithm>
#include <cstdio>
#include <cstdlib>
#include <cmath>
using namespace std;
const int N=1000+5,M=200+5;
const int mod=1e9+7;
char s1[N],s2[M];
int n,m,K;
int dp[2][N][M],sum[2
][N][M]; //dp[i][j][k]=Σdp[i-1][j‘][k-1](1<=j‘<=j-1) +dp[i-1][j-1][k] int main(){ scanf("%d%d%d%s%s",&n,&m,&K,s1+1,s2+1); memset(dp,0,sizeof dp); memset(sum,0,sizeof sum); int I=0,J=1; for (int i=1;i<=n;i++){ if (s2[1]==s1[i]) dp[0][i][1]=1; sum[0][i][1]=sum[0][i-1][1]+dp[0][i][1]; } for (int i=2;i<=m;i++,I^=1,J^=1){ memset(dp[J],0,sizeof dp[J]); memset(sum[J],0,sizeof sum[J]); for (int j=1;j<=n;j++){ if (s2[i]!=s1[j]) continue; for (int k=1;k<=K;k++) if (j>=2) dp[J][j][k]=(sum[I][j-1][k-1]+dp[I][j-1][k])%mod; else dp[J][j][k]=dp[I][j-1][k]; } for (int k=1;k<=K;k++) for (int j=1;j<=n;j++) sum[J][j][k]=(sum[J][j-1][k]+dp[J][j][k])%mod; } printf("%d",sum[I][n][K]); return 0; }



Vijos[1982]NOIP2015Day2T2 子串 substring 動態規劃