当前位置: 代码迷 >> 综合 >> Codeforces Problem 711E ZS and The Birthday Paradox(抽屉原理+乘法逆元+费马小定理+组合数+快速幂+概率论)
  详细解决方案

Codeforces Problem 711E ZS and The Birthday Paradox(抽屉原理+乘法逆元+费马小定理+组合数+快速幂+概率论)

热度:39   发布时间:2023-12-12 09:57:20.0

此文章可以使用目录功能哟↑(点击上方[+])

比赛链接→Codeforces Round #369 (Div. 2)

 Codeforces Problem 711E ZS and The Birthday Paradox

Accept: 0    Submit: 0
Time Limit: 2 seconds    Memory Limit : 256 megabytes

 Problem Description

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 days in a year. ZS the Coder wants to interview k people from Udayland, each of them has birthday in one of 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 . 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?≤?n?≤?10^18,?2?≤?k?≤?10^18), meaning that there are 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 days long year equals (A?≥?0, B?≥?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.

 Sample Input

3 2
1 3
4 3

 Sample Output

1 8
1 1
23 128

 Hint

In the first sample case, there are ?=?8 days in Udayland. The probability that 2 people have the same birthday among 2 people is clearly , so A?=?1, B?=?8.

In the second sample case, there are only ?=?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.

 Problem Idea

解题思路:

【题意】
在Udayland这个地方,一年有

现在随机调查k个人的生日(生日在哪一天是等可能性的),问至少有两个人生日在同一天的概率是多少

概率用最简分数表示,输出分子A与分母B,并对1000003取模,取模前需保证A,B互质


【类型】
抽屉原理+乘法逆元+费马小定理+组合数+快速幂+概率论

【分析】

题目求"至少有两个人的生日在同一天的概率"

显然,我们不可能去一一计算两个人生日在同一天的概率、三个人生日在同一天的概率、……、k个人生日在同一天的概率,然后再加起来

因为,一旦k比较大时,计算量也会大得没谱,更何况,概率也不好计算

这时,我们就该从反面考虑考虑


毋庸置疑,相较之下,后者要比前者容易计算

"任意两个人的生日都不在同一天"的情况数相当于从天中挑选k天进行随意排列

故"任意两个人的生日都不在同一天"的情况数为,总的情况数为(每个人的生日可以有种选择,故k个人总计种)

当然,由抽屉原理可以知道,当k>时,就算每天都安排一个人生日,但是还是会有k-个人多出来,这些人不管你分配到哪一天,都会使得某一天至少有两个人生日

故当k>时,至少有两个人的生日在同一天的概率为100%,故结果输出"1 1"

那么剩下的情况,即k≤,"至少有两个人的生日在同一天的概率"=1-"任意两个人的生日都不在同一天"

∴"至少有两个人的生日在同一天的概率"=


下面我们来计算这一部分:

因为分母很明显是以2为底的幂,故分子和分母的GCD值肯定也是以2为底的幂,暂时记为

那接下来,问题的关键就是求分子式中有多少个2

对于分子中第i项分子式,中有n个2,那该项分子式中2的个数就取决于i

例如i=4时,该项分子式有2个2;i=16时,该项分子式有4个2

那最终把每项分子式中2的个数加起来便是tmp值,故约分之后,结果为


因为结果需要取模,于是便涉及到了除法取模,然后理所应当的就需要用到乘法逆元


那么mod p 该怎么计算呢?直接快速幂显然不行,因为指数部分已经超出了__int64的范围

这时候就需要想到费马小定理,这样就可以进行降幂,然后再快速幂求解

逆元部分也是如此,可以通过费马小定理降幂之后再求解

那分子部分呢?

观察,可以发现,其实分子就是k-1个连续整数的乘积

那么当k-1≥mod时,k-1个连续整数中必有一个能被mod整除,这就意味着取模之后结果为0,那k-1个连续整数的乘积就是0

而当k-1<mod时,因为mod的值不大,所以我们可以暴力循环求出分子

【时间复杂度&&优化】
O(MOD+logk+logn)

题目链接→Codeforces Problem 711E ZS and The Birthday Paradox

 Source Code

/*Sherlock and Watson and Adler*/
#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<queue>
#include<stack>
#include<math.h>
#include<vector>
#include<map>
#include<set>
#include<bitset>
#include<cmath>
#include<complex>
#include<string>
#include<algorithm>
#include<iostream>
#define eps 1e-9
#define LL long long
#define PI acos(-1.0)
#define bitnum(a) __builtin_popcount(a)
using namespace std;
const int N = 200005;
const int M = 100005;
const int inf = 1000000007;
const int mod = 1000003;
bool check(__int64 n,__int64 k)
{__int64 s=1;for(int i=1;i<=n;i++){s*=2;if(s>=k)return false;}return true;
}
__int64 Quick_Mod(__int64 a,__int64 b)//快速幂
{__int64 res = 1,term = a % mod;while(b){if(b & 1) res = (res * term) % mod;term = (term * term) % mod;b >>= 1;}return res;
}
int main()
{__int64 n,k,A,B,tmp,i,GCD;scanf("%I64d%I64d",&n,&k);if(check(n,k)){puts("1 1");return 0;}B=Quick_Mod(2,n%(mod-1)*((k%(mod-1)-1+(mod-1))%(mod-1))%(mod-1));for(tmp=0,i=2;i<=k-1;i*=2)tmp+=(k-1)/i;GCD=Quick_Mod(2,tmp%(mod-1)*(mod-2)%(mod-1));B=B*GCD%mod;if(k-1>=mod)printf("%I64d %I64d\n",B,B);else{A=1;for(i=1;i<=k-1;i++)A=A*((Quick_Mod(2,n%(mod-1))-i+mod)%mod)%mod;A=A*GCD%mod;printf("%I64d %I64d\n",(B-A+mod)%mod,B);}return 0;
}

菜鸟成长记

  相关解决方案