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;
}
posted @ 2020-09-09 20:15  jasony_sam  阅读(122)  评论(0编辑  收藏  举报