https://www.luogu.com.cn/problem/AT3576
又盯了半个多小时才看懂之前写的是啥
妙妙组合数学思维题啊啊
首先不管\(s,t\),要拿红球肯定是从\(1\)开始拿,不亏
假设要拿第一个蓝球了,那么我们可以把\(t\)设到当前蓝球第一个位置,不亏
假设\(t\)那个位置已经没有球了,但还是想要拿篮球,那把\(s\)设到现在蓝球的第一个位置,不亏
然后就可以考虑计算了
假设从\(t\)处拿了\(i\)个蓝球,那么要从\(1\)处拿\(B-i\)个蓝球,才能让\(t\)那个位置没有球,进入第三步
假设从\(s\)处拿了\(j\)个蓝球,那么要从\(1\)处拿走\(B-i-j\)个红球,才能让\(s\)处没有球
第一个是\(\large \binom{B-1}{i-1}\),因为第一个拿了肯定是蓝球,随意上下都要\(-1\),同理,第二个是\(\large \binom{B-i-1}{j-1}\)
还剩下\(A-(B-i)-(B-i-j)\)个红球,可以在\(s,t\)拿蓝球之前,第二步之后任意取,共\(3\)段,用插板法可得为
\(\large \binom{A-(B-i)-(B-i-j)-1}{3-1}\)
(剩下的蓝球只能从\(A\)处一个个取了)
因为上面那种只考虑的分成三段的情况,实际上可以蓝色整个作为一段,那样的方案数是\(A+1\)的,单独加上即可
code:
#include<bits/stdc++.h>
#define ll long long
#define N 4050
#define mod 1000000007
using namespace std;
int a, b, c[N][N];
int C(int n, int m) {
if(m > n || n < 0 || m < 0) return 0;
return c[n][m];
}
int main() {
scanf("%d%d", &a, &b);
for(int i = 0; i <= a + b; i ++) c[i][0] = 1;
for(int i = 1; i <= a + b; i ++)
for(int j = 1; j <= i; j ++)
c[i][j] = (c[i - 1][j] + c[i - 1][j - 1]) % mod;
ll ans = a + 1;
for(int i = 1; i <= b; i ++)
for(int j = 1; j <= b - i; j ++)
ans = (ans + 1ll * C(b - 1, i - 1) * C(b - 1 - i, j - 1) % mod * C(a - (b - i) - (b - i - j) + 2, 2) % mod) % mod;
printf("%lld", ans);
return 0;
}