题目链接:
https://ac.nowcoder.com/acm/contest/881/E
题意:
有一串长度为2(n + m)且只有AB两种字符的字符串(A、B字符个数相同),能够将其分解为n个AB和m个BA子串。
给你n和m,问有多少种可能的字符串。
题解:
①策略
对于A, 变为AB;对于B, 变为BA
②约束条件:
当前A的最大值 = 未能匹配的A的最大值(想变成AB的最大值为n) + 已经匹配的BA(B的个数)的个数, B同理
即
A
<
=
B
+
n
A <= B + n
A<=B+n 和
B
<
=
A
+
m
B <= A + m
B<=A+m
③转移方程:
f
[
i
]
[
j
]
=
f
[
i
−
1
]
[
j
−
1
]
+
f
[
i
−
1
]
[
j
]
f[i][j] = f[i - 1][j - 1] + f[i - 1][j]
f[i][j]=f[i−1][j−1]+f[i−1][j]
即前一步基础上放A + 前一步基础上放B
④优化:
注意到
f
[
i
]
f[i]
f[i]的状态只和
f
[
i
−
1
]
f[i - 1]
f[i−1]有关, 可以用滚动数组优化空间
代码:
const int MAX = 2e3 + 10;
const ll mod = 1e9 + 7;
int n, m;
ll f[2][MAX];//前i个位置放j个A, i - j个B
int main() {
while (~scanf("%d%d", &n, &m)) {
f[0][0] = 1;
for (int i = 1; i <= 2 * (n + m); i++) {
int now = i % 2, pre = now ^ 1;
for (int j = 0; j <= i; j++)//放j个A
if (j <= n + m && i - j <= n + m) {
f[now][j] = 0;
if (2 * j - i <= n && i - 2 * j <= m) {
if (j >= 1)//当前状态A的个数>=1 才有可能是上一个状态放了A
(f[now][j] += f[pre][j - 1]) %= mod;
if (i - j >= 1)//放B同理
(f[now][j] += f[pre][j]) %= mod;
}
}
}
printf("%lld\n", f[(2 * (n + m)) % 2][n + m]);
}
return 0;
}