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

子串 (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;
}



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章