题解
%%% Factorio F a c t o r i o 神犇!!!
这里介绍一种奇妙的做法,不难理解,代码也很好写。
其实并不需要考虑每种情况下
s,t
s
,
t
具体是多少,只需要根据当前情况需要再决定,可以证明以下情况都是存在
s,t
s
,
t
使之成立的:
这里设
s<t
s
<
t
,初始有
A
A
个红球,个蓝球可以把取球分成三个部分的动作:
- t t 位置未变空
- 位置变空, s s 位置未变空
- 均变空,此时只能从 1 1 位置取球
显然第部分取球的序列是由前
2
2
部分决定且唯一的,所以不再考虑。
蓝球全部连续出现的情况太过特殊,在这里单独列出连续出现的情况数为。接下来讨论到的情况都是蓝球存在间隔出现的情况:
进一步把
1,2
1
,
2
过程细分:
1.1. 取出一些红球
1.2. 取出第一个蓝球,取出总共
B
B
个球,其中含有个蓝球。
2.1. 取出一些红球
2.2. 取出第一个蓝球,取出总共
B−i
B
−
i
个球,其中含有
j
j
个蓝球。
这样便枚举到了所有可能的情况,想象即使可能的取值并不支持在1.2.取出
B
B
个球,但之后的操作也会出现同样的效果,把前移是等效的。
这个不好证明,感性理解,我认真想了还是不会啊TAT。
所以统计答案只需要枚举
i,j
i
,
j
,再利用组合计数计算出当前
i,j
i
,
j
下的方案数:
首先需要满足
B−i+B−i−j≤a
B
−
i
+
B
−
i
−
j
≤
a
,方案数:
(B−1i−1)(B−i−1j−1)(A−(2B−2i−j)+22)
(
B
−
1
i
−
1
)
(
B
−
i
−
1
j
−
1
)
(
A
−
(
2
B
−
2
i
−
j
)
+
2
2
)
这里用到隔板法,
(B−1i−1)
(
B
−
1
i
−
1
)
指把
B
B
个球放进个箱子,每个箱子至少放一个的方案数,这里具体指1.2.中有
i
i
个蓝球,把个球任意放进
i
i
个蓝球之后的方案。同理可得,表示2.2.的情况。
(A−(2B−2i−j)+22)
(
A
−
(
2
B
−
2
i
−
j
)
+
2
2
)
则表示除掉1.2. 2.2.两次放入的红球外,剩余的红球分别在1.1. 2.1. 3.任意个数(某次可以为空)全部放入的方案数。
组合数预处理一下即可。
代码
#include<bits/stdc++.h>
using namespace std;
const int mod=1e9+7,N=2050;
int a,b,c[N][N],ans;
inline int ad(int x,int y){x+=y;if(x>=mod) x-=mod;return x;}
inline int mul(int x,int y){return 1ll*x*y%mod;}
int main(){
int i,j;
c[0][0]=1;
for(i=1;i<N;++i){
c[i][0]=c[i][i]=1;
for(j=1;j<i;++j) c[i][j]=ad(c[i-1][j-1],c[i-1][j]);
}
scanf("%d%d",&a,&b);
ans=a+1;
for(i=max(1,b-a);i<b;++i)
for(j=max(1,2*(b-i)-a);j<=b-i;++j)
ans=ad(ans,mul(mul(c[b-1][i-1],c[b-i-1][j-1]),c[a-2*(b-i)+j+2][2]));
printf("%d\n",ans);
}