题目链接:点击这里
题目大意:
一共有
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!}
Cmc1Cm−c1c2...Cm−∑i=1n−1cicn=∏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!}
365m∏cnt!∏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(365m∏cnt!∏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!−log10365m−log10∏cnt!−log10i=1∏nci!
=
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(365−n)!+log10n!+log10m!−mlog10365−∑log10cnt!−i=1∑nlog10ci!
=
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(365−n)!+log10m!−mlog10365−∑log10cnt!−i=1∑nlog10ci!
故可以先处理出
m
=
∑
i
=
1
n
c
i
≤
36500
m=\sum_{i=1}^nc_i\le36500
m=∑i=1nci≤36500 以内的阶乘,然后
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;
}