Codeforces 711E ZS and The Birthday Paradox
传送门
time limit per test 2 seconds
memory limit per test 256 megabytes
input standard input
output standard output
ZS the Coder has recently found an interesting concept called the Birthday Paradox. It states that given a random set of \(23\) people, there is around \(50\%\) chance that some two of them share the same birthday. ZS the Coder finds this very interesting, and decides to test this with the inhabitants of Udayland.
In Udayland, there are \(2^n\) days in a year. ZS the Coder wants to interview \(k\) people from Udayland, each of them has birthday in one of \(2^n\) days (each day with equal probability). He is interested in the probability of at least two of them have the birthday at the same day.
ZS the Coder knows that the answer can be written as an irreducible fraction \(\dfrac{A}{B}\). He wants to find the values of \(A\) and \(B\) (he does not like to deal with floating point numbers). Can you help him?
Input
The first and only line of the input contains two integers \(n\) and \(k\) (\(1 \le n \le 10^18, 2 \le k \le 10^18\)), meaning that there are \(2^n\) days in a year and that ZS the Coder wants to interview exactly \(k\) people.
Output
If the probability of at least two \(k\) people having the same birthday in \(2^n\) days long year equals (\(A \ge 0, B \ge 1, \gcd(A,B)=1\)), print the \(A\) and \(B\) in a single line.
Since these numbers may be too large, print them modulo \(10^6 + 3\). Note that \(A\) and \(B\) must be coprime before their remainders modulo \(10^6 + 3\) are taken.
Examples
Input
3 2
Output
1 8
Input
1 3
Output
1 1
Input
4 3
Output
23 128
Note
In the first sample case, there are \(2^3 = 8\) days in Udayland. The probability that \(2\) people have the same birthday among \(2\) people is clearly \(\frac{1}{8}\) , so \(A = 1, B = 8\).
In the second sample case, there are only \(2^1 = 2\) days in Udayland, but there are \(3\) people, so it is guaranteed that two of them have the same birthday. Thus, the probability is \(1\) and \(A = B = 1\).
Solution
首先注意到\(10^6+3\)是个素数.
不难想到求任意两人生日都不冲突的概率更为简单, 答案是\(\dfrac{A_{2^n}^{k}}{2^{nk}}\), 展开化简得
这里我们需要注意:
因为\(\gcd(a, b)=\gcd(a, b-a)\).
接着要对此式进行约分, 也就是求分子的素因子分解形式中2的幂次. 这里有个key observation:
\[2^n-x中2的幂次和x中2的幂次相同. \]
所以问题转化成求\((k-1)!\)中所包含的2的幂次.
而\(n!\)中包含的素数\(p\)的幂次, 记作\(\nu_p(n!)\), 为:
\[\nu_p(n!)=\sum_{i\ge 1}[\frac{n}{p^i}] \]
上式也称作Legendre's formula.
注意: 如果\(p\)不是素数, 这个结论是不成立的.
Implementation
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
// return the max k s.t. p^k | n!
LL get_exponent(LL n, int p){
LL res=0;
for(LL x=p; n>=x; res+=n/x, x*=p);
return res;
}
LL Pow(LL x, LL n, int p){
LL res=1;
for(; n; x*=x, x%=p, n>>=1)
if(n&1) res*=x, res%=p;
return res;
}
// return 2^{(k-1)*n}
LL calc2(LL n, LL k, int p){
return Pow(Pow(2, k-1, p), n, p);
}
// x cannot be divided by p
LL inv(LL x, int p){
return Pow(x, p-2, p);
}
// A(n, k)%p, p is small
// n>=k
LL calc3(LL n, LL k, int p){
if(k>=p) return 0;
LL res=1;
for(; k; ){
res*=n, res%=p;
if(n==0) break;
--k, --n;
}
return res;
}
int main(){
LL n, k;
cin>>n>>k;
int p=1000003;
if(log2(k)>n){
puts("1 1");
}
else{
LL cnt=get_exponent(k-1, 2); //error-prone
LL x=Pow(2, cnt, p);
LL y=(Pow(2, n, p)+p-1)%p;
LL t=inv(x, p);
LL num=calc3(y, k-1, p)*t%p;
LL den=calc2(n, k, p)*t%p;
num=(den-num+p)%p; //error-prone
cout<<num<<' '<<den<<endl;
}
}
Pitfalls
最近写代码总是犯各种各样的傻逼错误. 比如这次我把函数calc2()
中的return Pow(Pow(2, k-1, p), n, p);
写成了Pow(Pow(2, k-1, p), n, p);
. 这样在本地竟然把3个样例都过了. 然后交上去竟然WA on T1.
历尽千辛万苦才找到bug. 我的编译器(g++ 5.4.0)没报错, 可能是自动识别了这个错误. 避免这个问题的方法是编译时加上-Wall
选项.
g++ main.cpp -o main -Wall -std=c++14 && ./main <in