Codeforces 711E ZS and The Birthday Paradox

链接

传送门

题意

一年有\(2^n(1 \leq n \leq 10^{18})\)天,有\(k(2 \leq k \leq 10^{18})\)个人,求至少两人生日相同的概率。

思路

\(k > 2^n\)时,\(p=1\)

\(k \leq 2^n\)时,有\[p=1-\frac{(2^n - 1)(2^n - 2) \cdots (2^ n - k + 1)}{2^{(k - 1)n}}=\frac{b-a}{b}\]

可以在\(O(\log k)\)的时间内求出\(\gcd(a,b)\)

对于\(a\),若\(k-1 > mod\),则\(a=0\)。否则可以枚举求解。

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
#include <cstdio>

using namespace std;

typedef long long LL;

const LL mod = 1000003;

LL pow_mod(LL x, LL k) {
LL res = 1, cur = x;
while (k) {
if (k & 1) {
res = res * cur % mod;
}
cur = cur * cur % mod;
k >>= 1;
}
return res;
}

int main() {
LL n, k;
scanf("%lld%lld", &n, &k);
if (n < 63 && (1LL << n) < k) {
puts("1 1");
return 0;
}
LL tmp = 0, pow2_n = pow_mod(2, n);
for (LL i = 2; i < k; i <<= 1) {
tmp += (k - 1) / i;
}
LL gcd_inv = pow_mod(pow_mod(2, mod - 2), tmp);
LL a = 1, b = pow_mod(pow2_n, k - 1) * gcd_inv % mod;
if (k > mod) {
a = b;
} else {
for (int i = 1; i < k; ++i) {
a = a * (pow2_n - i + mod) % mod;
}
a *= gcd_inv;
a = ((b - a) % mod + mod) % mod;
}
printf("%lld %lld\n", a, b);
return 0;
}