CF711E ZS and The Birthday Paradox
Solution
原题最后的答案比较难求,所以我们可以反方向思考:只需要求出所有人生日不同的概率。
显然这个概率为 \(\dfrac{A_{2^n}^m}{2^{nm}}=\dfrac{\prod_{i=2^n-m+1}^{2^n-1}}{2^{n(m-1)}}\) 。
分母部分用快速幂即可,而分子部分需要我们思考一下,因为模数为 \(10^6+3\) ,当 \(m\) 大于模数时,分子的因数必有一项为模数的倍数,答案可输出 \(0\) ,其他情况暴力求解即可。
但是,这个题还有一个需要注意的地方是分数的约分。因为分母为 \(2\) 的幂,所以找出分子中 \(2\) 的幂次即可。这里用到了 \(Legendre's~formula\) 。因为对于所有 \(1\leq a\leq 2^n\) ,都有 \(a\) 与 \(2^n-a\) 的 \(2\) 的幂次相同,所以求出 \((m-1)!\) 中的 \(2\) 的次数就好了。
时间复杂度: \(O(\log k+\log n)\)
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
using namespace std;
const int mod=1e6+3;
ll n,k,num=0,fz=1,fm=1;
ll fpow(ll a,ll b){
ll res=1;
while(b){
if(b&1) res=res*a%mod;
a=a*a%mod;
b>>=1;
}
return res;
}
int main(){
scanf("%lld%lld",&n,&k);
num=1;
while((1LL<<num)<k) num++;
if(num>n){
printf("1 1");
return 0;
}
num=0;
for(ll i=k-1;i>=1;i>>=1) num+=(i>>1);
ll a=fpow(2,n);
fz=1;
for(int i=1;i<k;i++){
fz=(ll)fz*(a-i+mod)%mod;
if(fz==0) break;
}
fm=fpow(a,k-1);
int inv=fpow(fpow(2,num),mod-2);
fz=(ll)fz*inv%mod,fm=(ll)fm*inv%mod;
fz=(fm-fz+mod)%mod;
printf("%lld %lld",fz,fm);
return 0;
}