標籤:string 不同 typedef 方案 優秀 沒有 包含 lin alt
P2679 子串
題意題目描述
有兩個僅包含小寫英文字母的字串\(A\)和\(B\)。
現在要從字串\(A\)中取出\(k\)個互不重疊的非空子串,然後把這\(k\)個子串按照其在字串\(A\)中出現的順序依次串連起來得到一個新的字串。請問有多少種方案可以使得這個新串與字串\(B\)相等?
注意:子串取出的位置不同也認為是不同的方案。
輸入輸出格式輸入格式:
第一行是三個正整數\(n,m,k\),分別表示字串\(A\)的長度,字串\(B\)的長度,以及問題描述中所提到的\(k\),每兩個整數之間用一個空格隔開。
第二行包含一個長度為\(n\)的字串,表示字串\(A\)。
第三行包含一個長度為\(m\)的字串,表示字串\(B\)。
輸出格式:
一個整數,表示所求方案數。
由於答案可能很大,所以這裡要求輸出答案對\(1000000007\)模數的結果。
輸入輸出範例輸入範例:
6 3 1aabaabaab
輸出範例:
2
輸入範例:
6 3 2aabaabaab
輸出範例:
7
輸入範例:
6 3 3aabaabaab
輸出範例:
7
說明
對於第\(1\)組資料:\(1 \leq n \leq 500,1 \leq m \leq 50,k=1\);
對於第\(2\)組至第\(3\)組資料:\(1 \leq n \leq 500,1 \leq m \leq 50,k=2\);
對於第\(4\)組至第\(5\)組資料:\(1 \leq n \leq 500,1 \leq m \leq 50,k=m\);
對於第\(1\)組至第\(7\)組資料:\(1 \leq n \leq 500,1 \leq m \leq 50,1 \leq k \leq m\);
對於第\(1\)組至第\(9\)組資料:\(1 \leq n \leq 1000,1 \leq m \leq 100,1 \leq k \leq m\);
對於所有\(10\)組資料:\(1 \leq n \leq 1000,1 \leq m \leq 200,1 \leq k \leq m\)。
思路
你可以看一篇優秀的部落格。 --alecli
這位神犇叫為了我這道題。
設計狀態\(dp[i][j][k][0/1]\),\(i\)表示\(A\)字串的前\(i\)位,\(j\)表示\(B\)字串的前\(j\)位,\(k\)表示選取了多少個子串,\(0/1\)表示當前字元有沒有選入子串中。
如果該位沒有選,那麼轉移是顯然易見的:
\[dp[i][j][k][0]=dp[i-1][j-1][k][1]+dp[i-1][j-1][k][0]\]
它表示不論前一位選與不選,我都加一個空格,分開上一子串和下一子串
而如果要選這一位,就要分類討論這一位上的\(A\)與\(B\)是否相同。
- 如果不同,那麼\(dp[i][j][k][0]=0\);
- 如果相同,那麼\(dp[i][j][k][0]=dp[i-1][j-1][k][1]+dp[i-1][j-1][k-1][1]+dp[i-1][j-1][k-1][0]\),它表示繼續下一子串、在上一子串聯續的情況下重新開始新一子串、直接作為新子串的開頭。
那麼答案就是\(dp[n][m][k][0]+dp[n][m][k][1]\)了。
順便,My Code怕空間不足,寫了滾動數組。如果不寫的話,要記得初始化\(dp\)數組的值。
AC代碼
#include<bits/stdc++.h>using namespace std;typedef long long LL;const LL P=1000000007;LL n,m,k,dp[2][202][202][2];string a,b;int main(){ cin>>n>>m>>k; cin>>a>>b; a=' '+a; b=' '+b; dp[0][0][0][0]=dp[1][0][0][0]=1; for(LL i=1;i<=n;i++) for(LL j=1;j<=m;j++) for(LL p=1;p<=k;p++) { dp[i&1][j][p][0]=(dp[(i-1)&1][j][p][0]+dp[(i-1)&1][j][p][1])%P; if(a[i]==b[j]) dp[i&1][j][p][1]=(dp[(i-1)&1][j-1][p][1]+dp[(i-1)&1][j-1][p-1][0]+dp[(i-1)&1][j-1][p-1][1])%P; else dp[i&1][j][p][1]=0; } printf("%lld",(dp[n&1][m][k][1]+dp[n&1][m][k][0])%P); return 0;}
Luogu P2679 子串(字串+dp)