原题地址:https://ac.nowcoder.com/acm/contest/881/E
思路:定义
d
p
[
i
]
[
j
]
dp[i][j]
dp[i][j]表示有
i
i
i个
A
A
A,
j
j
j个
B
B
B的方案数.
首先,这样子定义,转移就很容易写,你就枚举当前串后面再添一个
A
A
A还是
B
B
B,所以也就是
dp[i + 1][j] += dp[i][j];
dp[i][j + 1] += dp[i][j];
所以现在的问题是如何确定一个串是由 n n n个 A B AB AB并且由m个 B A BA BA
我们考虑之前 d p dp dp定义的前缀 i i i个 A A A和 j j j个 B B B,进一步思考如果 i − j > k i-j>k i−j>k,那么这个串至少会产生 k k k个 A B AB AB(因为如果在某个前缀的时候你 i − j = k i-j=k i−j=k,那么必然有 k k k个 A A A只能与后面的 B B B匹配),同理, j − i j-i j−i也是一样的.
所以对于题目中描述的 n n n个 A B AB AB, m m m个 B A BA BA,只需要 d p dp dp时候注意合法的转移就可以了.也就是说 i − j > n i-j>n i−j>n并且 j − i > m j-i>m j−i>m,每次转移的注意一下就可以了.
#include <bits/stdc++.h>
#define eps 1e-8
#define INF 0x3f3f3f3f
#define PI acos(-1)
#define lson l,mid,rt<<1
#define rson mid+1,r,(rt<<1)+1
#define CLR(x,y) memset((x),y,sizeof(x))
#define fuck(x) cerr << #x << "=" << x << endl
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int seed = 131;
const int maxn = 1e5 + 5;
const int mod = 1e9 + 7;
ll dp[2004][2005];
//dp[i][j]表示前缀有i个A,有j个B的方案数
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 <= m + n; j++) {
if (i - j < n)dp[i + 1][j] += dp[i][j];
if (j - i < m)dp[i][j + 1] += dp[i][j];
dp[i + 1][j] %= mod;
dp[i][j + 1] %= mod;
}
}
printf("%lld\n", dp[n + m][n + m]);
}
return 0;
}