題意:問你長度為2 * (n+m)的字符串由(n+m)個A和B組成,要求有n個AB子序列和m個BA子序列,這樣的串有幾個
https://ac.nowcoder.com/acm/contest/881/E
思路:
假設有一個合法串,因為子序列n個AB和m個BA,那么顯然有前n個A必為AB的A,前m個B必為BA的B。因為如果我前n個A中有一個是BA的A,那我是不是可以從更后面隨便找一個A給這個B用,那么顯然前n個A必為AB的A。
我們假設DP[i][j]為i個Aj個B,放A:
如果i < n那么可以直接放這個A,理由如上
如果i >= n,那么我們要確保這個A能給前面的B當BA用,那么當前BA需要的A是min(j, m)個,已經給他了i - n個,故(i - n) < min(j, m)則還可以繼續放。
代碼:
#include<cmath> #include<set> #include<map> #include<queue> #include<cstdio> #include<vector> #include<cstring> #include <iostream> #include<algorithm> using namespace std; typedef long long ll; typedef unsigned long long ull; const int maxn = 2e3 + 5; const int M = 50 + 5; const ull seed = 131; const int INF = 0x3f3f3f3f; const int MOD = 1e9 + 7; ll dp[maxn][maxn]; int main(){ int n, m; while(~scanf("%d%d", &n, &m)){ for(int i = 0; i <= n + m; i++){ for(int j = 0; j <= n + m; j++){ dp[i][j] = 0; } } dp[0][0] = 1; for(int i = 0; i <= n + m; i++){ for(int j = 0; j <= n + m; j++){ if(i < n || (i - n) < min(m, j)){ //push A dp[i + 1][j] = (dp[i + 1][j] + dp[i][j]) % MOD; } if(j < m || (j - m) < min(n, i)){ //push B dp[i][j + 1] = (dp[i][j + 1] + dp[i][j]) % MOD; } } } printf("%lld\n", dp[n + m][n + m]); } return 0; }