P1287 盒子与球

题目描述

现有 \(r\) 个互不相同的盒子和 \(n\) 个互不相同的球,要将这 \(n\) 个球放入 \(r\) 个盒子中,且不允许有空盒子。请求出有多少种不同的放法。

两种放法不同当且仅当存在一个球使得该球在两种放法中放入了不同的盒子。

输入格式

输入只有一行两个整数,分别代表 \(n\)\(r\)

输出格式

输出一行一个整数代表答案。

样例 #1

样例输入 #1

3 2

样例输出 #1

6

提示

样例输入输出 1 解释

有两个盒子(编号为 \(1, 2\))和三个球(编号为 \(1, 2, 3\)),共有六种方案,分别如下:

盒子编号 方案 1 方案 2 方案 3 方案 4 方案 5 方案 6
盒子 \(1\) 小球 \(1\) 小球 \(2\) 小球 \(3\) 小球 \(2, 3\) 小球 \(1, 3\) 小球 \(1, 2\)
盒子 \(2\) 小球 \(2, 3\) 小球 \(1, 3\) 小球 \(1, 2\) 小球 \(1\) 小球 \(2\) 小球 \(3\)

数据规模与约定

对于 \(100\%\) 的数据,保证 \(0 \leq r \leq n \leq 10\),且答案小于 \(2^{31}\)

分析

首先考虑:\(r\) 个球,\(n\) 个盒子,彼此互不相同,求将球全部放入盒中的方案数,允许空盒。

可以发现答案即为 \(n^r\),因为每一个小球的决策都不影响其他小球。

再来考虑:\(r\) 个球,\(n\) 个盒子,彼此互不相同,求将球全部放入盒中的方案数,至少 \(k\) 个空盒。

则只需要先选出哪些盒子是空的,再让剩下的小球随便分配即可。

答案即为:\(C_n^k\times (n-k)^r\)

再回到原来的题目,只需将随意分配的结果个数减去有空盒的即可。

根据容斥原理,可以得到有空盒的情况总数为 \(\large \Sigma_{k=1}^{n} (-1)^{k-1}\times C_n^k \times (n-k)^r\)

最终结果为:$$m^n-\large \Sigma_{k=1}^{n} (-1)^{k-1}\times C_n^k \times (n-k)^r$$

\[=m^n+\large \Sigma_{k=1}^{n} (-1)^k\times C_n^k \times (n-k)^r \]

\[=(-1)^0C_m^0(m-0)^n+\large \Sigma_{k=1}^{n} (-1)^k\times C_n^k \times (n-k)^r \]

\[=\large \Sigma_{k=0}^{n} (-1)^{k}\times C_n^k \times (n-k)^r \]

#include<bits/stdc++.h>
#define int long long
using namespace std;
inline int read(){
	int x=0,f=1;
	char c=getchar();
	while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
	while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
	return x*f;
}
int r,n,ans;
int qpow(int x,int y){
	int res=1;
	while(y){
		if(y&1)res*=x;
		x*=x,y>>=1;
	}
	return res;
}
int C(int n,int m){
	if(n<m)return 0;
	int res=1;
	for(int i=n;i>n-m;i--)res*=i,res/=(n-i+1);
	return res;
}
signed main(){
	r=read(),n=read();
	for(int i=0;i<n;i++)ans+=((i&1)?-1:1)*C(n,i)*qpow(n-i,r);
	cout<<ans<<endl;
	return 0;
}
posted @ 2023-06-24 19:42  alex_liu09  阅读(60)  评论(0)    收藏  举报