• 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_{2n}{k}}{2^{nk}}$, 展开化简得
    $$ frac{(2n-1)(2n-2)cdots(2n-(k-1))}{2{n(k-1)}} $$
    这里我们需要注意:
    $$dfrac{a}{b}既约Longleftrightarrow dfrac{a}{b-a}既约, (b>a)$$
    因为$gcd(a, b)=gcd(a, b-a)$.

    接着要对此式进行约分, 也就是求分子的素因子分解形式中2的幂次. 这里有个key observation:

    $$2^n-x中2的幂次和x中2的幂次相同.$$

    所以问题转化成求$(k-1)!$中所包含的2的幂次.
    而$n!$中包含的素数$p$的幂次, 记作$ u_p(n!)$, 为:

    $$ u_p(n!)=sum_{ige 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

  • 相关阅读:
    git 本地仓库操作
    git学习一——Pro-Git
    React Router
    webpack详述
    webpack入门
    折半查找法
    String的常见操作(面试题)
    Java集合(五)—HashMap源码
    Java常见操作符
    Java随机数
  • 原文地址:https://www.cnblogs.com/Patt/p/5861779.html
Copyright © 2020-2023  润新知