有兩個僅包含小寫英文字母的字符串A和B。html
如今要從字符串A中取出k個互不重疊的非空子串,而後把這k個子串按照其在字符串A中出現的順序依次鏈接起來獲得一個新的字符串。請問有多少種方案能夠使得這個新串與字符串B相等?數組
注意:子串取出的位置不一樣也認爲是不一樣的方案。ide
這道題是一道比較明顯的動態規劃。咱們先考慮劃分狀態。因爲要從字符串A中取出k個互不重疊的非空子串,使它們鏈接起來與B相等,咱們容易想到記錄在字符串A中已處理的長度、在字符串B中已處理的長度和已取出子串的個數。但這樣仍是難以將狀態轉移方程推出來。咱們考慮再加入一維來表示對於字符串A的當前這一位是否被選擇。這樣咱們就能夠開始推導方程式了。若是A的當前這一位不等於B的當前這一位,那麼意味着它不可能被選擇,因此它未被選擇的方案數即爲前一位選擇或者不選擇進當前當前子串兩種方案數的總和,而被選擇的方案數爲零;若是等於,那麼意味着它可選可不選,若選擇,則其方案數爲上一位選擇進這個子串、選擇進上個子串和不選擇的方案數的總和,若不選擇則與上一個狀況相同。spa
這樣,設fi,j,k,opt表示在字符串A中處理到第i個字符,字符串B中處理到第j個字符,當前選擇的是第k個子串,選擇當前字符的狀況爲opt(opt爲0指當前字符選入,opt爲1指當前字符不選入)的時候的方案總數,則有code
fi,j,k,0=∑{fi-1,j,l,1+fi-1,j,l,0},fi,j,k,1=A[i]==B[j]?∑{fi-1,j-1,l,1+fi-1,j-1,l-1,0+fi-1,j-1,l-1,1}:0(1<=l<=k)。
htm
但若是按照上面的方程,數組須要開到200*200*200*2,顯然是不可能的。咱們注意到,對於第一維,其實只用到了i和i-1兩個相鄰的狀態,因而咱們能夠運用滾動數組,將第一維所需空間滾動成2,空間就沒有問題了。blog
1 #include<algorithm> 2 #include<cstdio> 3 #include<cstring> 4 using namespace std; 5 int n,m,k,f[2][201][201][2]; 6 char a[1001],b[201]; 7 const int mod=1000000007; 8 int main() 9 { 10 scanf("%d%d%d%s%s",&n,&m,&k,a+1,b+1); 11 f[1][0][0][0]=f[0][0][0][0]=1; 12 for(int i=1;i<=n;++i) 13 for(int j=1;j<=m;++j) 14 for(int l=1;l<=k;++l) 15 { 16 f[i&1][j][l][0]=(f[i+1&1][j][l][1]+f[i+1&1][j][l][0])%mod; 17 f[i&1][j][l][1]=a[i]==b[j]?((f[i+1&1][j-1][l][1]+f[i+1&1][j-1][l-1][0])%mod+f[i+1&1][j-1][l-1][1])%mod:0; 18 } 19 printf("%d",(f[n&1][m][k][1]+f[n&1][m][k][0])%mod); 20 return 0; 21 }