CF711E ZS and The Birthday Paradox 题解
-
题意
求一年有 天, 个人出现两人生日相同的概率。答案输出对 的取模分子和分母(约分后)。
-
思路
-
首先想不进行优化的数学计算方法,求出两人生日相同的概率不容易,但我们可以求出所有人生日不同的概率(也就是排列数除以所有情况数),再用 减掉,即得公式
展开 得到
-
然后可以很容易想到用快速幂进行进行计算,求得分子和分母。
-
但是,题目要求约分。容易看出,分数线上下同除的数一定是 (因为分母是),且分子一定有剩余(不然答案就是 了),因此只要知道分子中可以分解出几个 就可以了。
-
于是,可以使用勒让德定理(但我不会证明)。
( 表示 质因数分解后 的指数)
-
这样,分子中可以分解出几个 就可以用勒让德定理求出。
下面讲一下具体的方法:
-
首先想到的是用 算出结果,但 ,显然TLE。
-
然后想到分类讨论分子的各个组成部分,首先, 中一定有 个 ,然后考虑之后每一项,可知每一项中 的个数取决于减去的数中 的个数,即而所有除 之外的项中 的个数就是每次减去的数中 的个数的和,也就是它们乘积中 的个数,即
此时可以计算。
-
-
所以,约分除去的数就是
可用快速幂求出。
-
最后一步,分子和分母同时乘需要除去的数的乘法逆元,答案就出来了。
-
-
注意
- 注意数据规模,要开
long long
,计算 时需要__int128
。 - 可以
#define int __int128
这时主函数类型要改,且注意输出时要强制转换为long long
(cout<<(long long)(......)<<......
),或者写输出函数(因为标准输入输出不支持__int128
),也要注意选择合适的编译器版本。 - 注意当 时直接输出
1 1
退出。 - 注意计算 时写成
1LL<<i
,不写LL
会炸。
- 注意数据规模,要开
-
代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
using namespace std;
const int mod=1e6+3;
int n,m;
bool check(){
int x=1;
for(int i=1;i<=n;i++){
x=x*2ll;
if(x>=m)
return false;
}
return true;
}
int qpow(int _n,int _k){
int ans=1ll;
while(_k) {
if(_k&1ll)
ans=ans*_n%mod;
_n=_n*_n%mod;
_k>>=1ll;
}
return ans;
}
int jian(int _a,int _b){
return (_a%mod-_b%mod+mod)%mod;
}
int getk(int _n){
int sum=0;
for(int i=1;_n/(1ll<<i)>0;i++){
sum+=_n/(1ll<<i);
}
return sum;
}
main(){
ll t_n,t_m;
cin>>t_n>>t_m;
n=t_n;m=t_m;
if(check()){
cout<<1<<" "<<1<<endl;
return 0;
}
int a=1;
for(int i=1;i<=m;i++){
a=a*jian(qpow(2,n),i-1)%mod;
if(a==0)break;
}
int b=qpow(2,n*m);
int k1=n;
int k2=getk(m-1);
int k=k1+k2;
int inv_k=qpow(k,mod-2);
cout<<(ll)((b*qpow(500002,k)%mod-a*qpow(500002,k)%mod+mod)%mod)<<" "<<(ll)(b*qpow(500002,k)%mod)<<endl;
return 0;
}
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来源 shicj's blog!
评论