【AT3576】Popping Balls(数数题)

题目链接

  • (n) 个红球和 (m) 个蓝球排成一行。
  • 你可以任意选定两个数 (x,y),然后执行 (n+m) 次取球操作,每次在第 (1)/(x)/(y) 个球中取走一个。
  • 求取出的球的颜色序列有多少种可能。
  • (1le n,mle2 imes10^3)

组合数学

选定不同的 (x,y) 可能取出相同的颜色序列这一点显得比较麻烦,考虑让每种颜色序列对应唯一的一种 (x,y)

比较显然,红球肯定可以视作是从 (1) 取的;蓝球优先视作从 (y) 取,其次视作从 (x) 取,最后视作从 (1) 取。

我们强定第一次取蓝球的位置就是 (y),因为真正的 (y) 肯定大于等于我们选中的这个 (y) ,而当其大于这个 (y) 时肯定不会更优。则接下来 (m) 步可以随意选择取红球或是蓝球, (m) 步后 (y) 位置上就没球了。

同理,强定之后第一次取蓝球的位置就是 (x),设 (y) 位置取走了 (i) 次蓝球,那么接下来 (m-i) 步可以随意选择取红球或是蓝球,(m-i) 步后 (x) 位置上就没球了,此后只能全部从 (1) 取。

于是,我们枚举在 (y) 位置取走了 (i) 次蓝球(取走了 (m-i) 次红球),(x) 位置取走了 (j) 次蓝球(取走了 (m-i-j) 次红球),由于第一次取的肯定是蓝球,方案数分别为 (C_{m-1}^{i-1})(C_{m-i-1}^{j-1})

剩下的 (n-(m-i)-(m-i-j)) 个红球可以分别放在 (y) 首次取球前、(x,y) 取球间、(x) 取完球后的三部分中(剩下的蓝球只能在 (x) 取完球后所有红球都取走后),利用插板法计算出方案数为 (C_{n-(m-i)-(m-i-j)+2}^2)

注意,上面的过程中假定了蓝球会分为从 (y) 取和从 (x) 取两部分,而没有考虑一次取走所有蓝球的情况,这一部分的方案数为 (n+1)

代码:(O(n^2))

#include<bits/stdc++.h>
#define Tp template<typename Ty>
#define Ts template<typename Ty,typename... Ar>
#define Rg register
#define RI Rg int
#define Cn const
#define CI Cn int&
#define I inline
#define W while
#define N 2000
#define X 1000000007
using namespace std;
int n,m,C[2*N+5][2*N+5];
I void Init(CI S) {RI i,j;for(C[0][0]=i=1;i<=S;++i) for(C[i][0]=j=1;j<=i;++j) C[i][j]=(C[i-1][j-1]+C[i-1][j])%X;}
int main()
{
	RI i,j,t;for(scanf("%d%d",&n,&m),t=n+1,Init(max(n+2,m)),i=1;i<=m;++i) for(j=1;j<=m-i;++j)//枚举在y,x位置上取走的蓝球数
		(m-i)+(m-i-j)<=n&&(t=(t+1LL*C[m-1][i-1]*C[m-i-1][j-1]%X*C[n-(m-i)-(m-i-j)+2][2])%X);return printf("%d
",t),0;//组合数计算方案数
}
败得义无反顾,弱得一无是处
原文地址:https://www.cnblogs.com/chenxiaoran666/p/AT3576.html