Birthday Paradox(组合数+概率)

题目链接:点击这里

题目大意:
一共有 m m m 人, n n n 个组,第 i i i 个组有 c i c_i ci 个人,表示这些人在同一个人过生日,不同组别一定不在同一天生日,求满足这个序列的概率,对结果取以 10 10 10 为底的对数

题目分析:
总可能情况为 36 5 m 365^m 365m ,我们考虑先对每个组划分日期,再将 m m m 人划分到 n n n 组内
n n n 个组划分日期的方案数为 C 365 n n ! C_{365}^nn! C365nn! ,此答案是默认 c i c_i ci 各不相同的,而实际并非如此,故要除去 ∏ c n t ! \prod cnt! cnt! (其中 c n t cnt cnt 为相同组合数目,比如 [ 1 , 1 , 1 , 2 , 2 ] [1,1,1,2,2] [1,1,1,2,2] ∏ c n t ! = 3 ! ∗ 2 ! \prod cnt!=3!*2! cnt!=3!2!),故真正的方案数为 C 365 n ∏ c n t ! \frac{C_{365}^n}{\prod cnt!} cnt!C365n
m m m 人划分到 n n n 组内的方案数为 C m c 1 C m − c 1 c 2 . . . C m − ∑ i = 1 n − 1 c i c n = m ! ∏ i = 1 n c i ! C_{m}^{c_1}C_{m-c_1}^{c_2}...C_{m-\sum_{i=1}^{n-1}c_i}^{c_n}=\frac{m!}{\prod_{i=1}^nc_i!} Cmc1Cmc1c2...Cmi=1n1cicn=i=1nci!m!
故概率为:
C 365 n n ! m ! 36 5 m ∏ c n t ! ∏ i = 1 n c i ! \frac{C_{365}^nn!m!}{365^m\prod cnt!\prod_{i=1}^n c_i!} 365mcnt!i=1nci!C365nn!m!
对其结果取以 10 10 10 为底的对数:
l o g 10 ( C 365 n n ! m ! 36 5 m ∏ c n t ! ∏ i = 1 n c i ! ) log_{10}(\frac{C_{365}^nn!m!}{365^m\prod cnt!\prod_{i=1}^n c_i!}) log10(365mcnt!i=1nci!C365nn!m!)
= l o g 10 C 365 n + l o g 10 n ! + l o g 10 m ! − l o g 10 36 5 m − l o g 10 ∏ c n t ! − l o g 10 ∏ i = 1 n c i ! =log_{10}C_{365}^n+log_{10}n!+log_{10}m!-log_{10}365^m-log_{10}\prod cnt!-log_{10}\prod_{i=1}^n c_i! =log10C365n+log10n!+log10m!log10365mlog10cnt!log10i=1nci!
= l o g 10 365 ! − l o g 10 n ! − l o g 10 ( 365 − n ) ! + l o g 10 n ! + l o g 10 m ! − m l o g 10 365 − ∑ l o g 10 c n t ! − ∑ i = 1 n l o g 10 c i ! =log_{10}365!-log_{10}n!-log_{10}(365-n)!+log_{10}n!+log_{10}m!-mlog_{10}365-\sum log_{10}cnt!-\sum_{i=1}^nlog_{10} c_i! =log10365!log10n!log10(365n)!+log10n!+log10m!mlog10365log10cnt!i=1nlog10ci!
= l o g 10 365 ! − l o g 10 ( 365 − n ) ! + l o g 10 m ! − m l o g 10 365 − ∑ l o g 10 c n t ! − ∑ i = 1 n l o g 10 c i ! =log_{10}365!-log_{10}(365-n)!+log_{10}m!-mlog_{10}365-\sum log_{10}cnt!-\sum_{i=1}^nlog_{10} c_i! =log10365!log10(365n)!+log10m!mlog10365log10cnt!i=1nlog10ci!
故可以先处理出 m = ∑ i = 1 n c i ≤ 36500 m=\sum_{i=1}^nc_i\le36500 m=i=1nci36500 以内的阶乘,然后 O ( n ) O(n) O(n) 计算该式子

具体细节见代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<vector>
#include<queue>
#include<set>
#include<map>
#define ll long long
#define inf 0x3f3f3f3f
#define Inf 0x3f3f3f3f3f3f3f3f
#define int ll
using namespace std;
int read()
{
	int res = 0,flag = 1;
	char ch = getchar();
	while(ch<'0' || ch>'9')
	{
		if(ch == '-') flag = -1;
		ch = getchar();
	}
	while(ch>='0' && ch<='9')
	{
		res = (res<<3)+(res<<1)+(ch^48);//res*10+ch-'0';
		ch = getchar();
	}
	return res*flag;
}
const int maxn = 36505;
const int maxm = 5005;
const int mod = 998244353;
const double pi = acos(-1);
const double eps = 1e-8;
int n,m,c[maxn],cnt[maxn];
double lgfac[maxn];
signed main()
{
	for(int i = 1;i < maxn;i++) lgfac[i] = lgfac[i-1]+log10(i);
	n = read();
	for(int i = 1;i <= n;i++) 
	{
		cnt[c[i] = read()]++;
		m += c[i];
	}
	double ans = lgfac[365]-lgfac[365-n]+lgfac[m]-m*log10(365);
	for(int i = 1;i <= n;i++) ans -= lgfac[c[i]];
	for(int i = 1;i < maxn;i++) ans -= lgfac[cnt[i]];
	printf("%.10f\n",ans);
	return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值