YZOJ P4621 [CSP-S 2019 四校联训 Round 1]生日悖论
时间限制:1000MS 内存限制:131072KB
难度:\(5.0\)
-
题目描述
一共有 \(N\) 种数字,所以按照包含数字的集合分类,可能有 \(2^N\) 类不同的集合。每个集合包含一种特定的数字的概率都是 \(\displaystyle\frac{1}{2}\) 。
随机取其中 \(k\) 个集合,请你帮忙算一下其中存在两个集合完全相同的概率。
-
输入格式
一行两个整数 \(N,k\) 。
-
输出格式
两个正整数,分别表示概率(最简分数)的分子和分母。分别对 \(10^6+3\) 取模吧。
-
数据规模与约定
\(1 \leq N \leq 10^{18}\),\(2 \leq k \leq 10^{18}\) 。
Source: CodeForces 711E ZS and The Birthday Paradox
若 \(2^N<K\) ,答案为 \(1\) 。
否则答案为 \(\displaystyle 1- \frac{P_{2^N}^{K}}{{2^N}^K}\) 。
发现这两的 \(\gcd\) 肯定是 \(2\) 的某个次幂,并且分母中因子 \(2\) 的个数肯定比分子多。
同时约掉 \(2^N\),要在分子 \(\displaystyle\frac{P_{2^N}^{K}}{2^N} = (2^N-1)(2^N-2)\cdots(2^N-K+1)\) 中找出因子 \(2\) 的个数。
注意到 \(\left|-K+1\right|\) 中因子 \(2\) 的个数肯定比 \(2^N\) 少,所以只需要找出 \(1, 2, \cdots, K-1\) 中每个数各包含因子 \(2\) 的个数。
为 \(\displaystyle \left\lfloor\frac{K-1}{2}\right\rfloor + \left\lfloor\frac{K-1}{4}\right\rfloor + \cdots + \left\lfloor\frac{K-1}{2^i}\right\rfloor\),其中 \(i\) 为满足 \(2^i \leq K-1\) 最大的整数。
这样 \(\gcd\) 和分母就解决了,剩下分子还没算出来。
根据抽屉原理,若 \(K-1 \geq MOD\) 则连续的 \(K-1\) 个数乘积一定包含 \(MOD\) 的倍数,即分子为 \(0\) ;
否则因为 \(MOD\) 比较小,暴力算即可。
最后逆元算一下即可。
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 |
#include <cstdio> #include <cstdlib> #include <cstring> #include <climits> #define MOD 1000003 inline int _pow(register int base,register long long b) { register int ans=1; while(b) { if(b&1) ans=(long long)ans*base%MOD; base=(long long)base*base%MOD; b>>=1; } return ans; } int main() { long long N,K; scanf("%lld%lld",&N,&K); if(N<=60 && ((long long)1<<N)<K) { printf("%d %d\n",1,1); return 0; } long long pw2=2,num=0; for(;pw2<=K-1;pw2*=2) num+=(K-1)/pw2; long long ans=1; if(K-1<MOD && (pw2=_pow(2,N))) for(register int i=1;i<=K-1 && ans;i++) (ans*=(pw2-i+MOD))%=MOD; else ans=0; register int invgcd=_pow(_pow(2,num),MOD-2); register long long low=(long long)_pow(_pow(2,K-1),N)*invgcd%MOD; printf("%lld %lld\n",(low-ans*invgcd%MOD+MOD)%MOD,low); return 0; } |