把博客园图标替换成自己的图标
把博客园图标替换成自己的图标end

【AT3576】Popping Balls(数数题)

题目链接

  • \(n\) 个红球和 \(m\) 个蓝球排成一行。
  • 你可以任意选定两个数 \(x,y\),然后执行 \(n+m\) 次取球操作,每次在第 \(1\)/\(x\)/\(y\) 个球中取走一个。
  • 求取出的球的颜色序列有多少种可能。
  • \(1\le n,m\le2\times10^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\n",t),0;//组合数计算方案数
}
posted @ 2021-10-10 19:57  TheLostWeak  阅读(64)  评论(0编辑  收藏  举报