// 侧边栏目录 // https://blog-static.cnblogs.com/files/douzujun/marvin.nav.my1502.css //目录导航 //生成目录索引列表

C. 简单的玄学

题目描述

\(m\) 个在 \([0,2^n)\) 内均匀随机取值的整型变量,求至少有两个变量取值相同的概率.

为了避免精度误差,假设你的答案可以表示成 \(a/b\) 的形式(其中\((a,b) = 1\) ),你需要输出 \(a\)\(b\)\(10^6+3\) 取模后的值.

对于 \(70\%\) 的数据, \(m \le 10^6\)
对于 \(100\%\) 的数据 ,\(1 \le 10^{18}\)\(2 \le m \le 10^{18}\)

【样例1输入】

3 2

【样例1输出】

1 8

【样例2输入】

1 3

【样例2输出】

1 1

【样例3输入】

4 3

【样例3输出】

23 128

基本思路

首先考虑正难则反,与其计算重合概率不如计算没有一个重合的概率,于是有:

\[1 - \frac{2^n * (2^n -1)* (...) * (2^n -m +1)}{2^{nm}} \]

接下来先思考如何约分,首先我们先观察到一个特殊性质。\(m \ge mod\) 时,分子上一定存在一项对 \(mod\) 取模后为零的项。但由于我们是先对后面的分子约分,再计算答案,所以我们还不能直接抛出\(1\ 1\)

然后我们真正来思考如何给分子和分母约分,自然我们只能在分子累乘的那几项中动手脚。

我们很容易观察到分子都是二的次幂减去一个数,在二进制下我们十分容易观察到一个性质,对于任意 \(2^n -i = j\),都有 \(j\) 的二的约数个数(即指数),等于 \(i\) 的二的约数个数

举几个例子,\(8 - 2\)\((1000)_2 - (0010)_2 = (0110)_2\)

而我的同学 zsk(luogu @zk_zk) 给出了更为可靠的证明:
我们设 \(i = q * 2^{k1}\)\(j = p * 2^{k2}\)

其中\(p\)\(q\) 均没有 \(2\) 因子.

\(2^n = q * 2^{k1} + p * 2^{k2}\)

我们不妨设 \(k1 \le k2\)\(k2 - k1 =x\)

故有 \(2^n = 2^{k1} * (p + q * 2^x)\)

而其中 \(2^{k1} \le 2^n\)\(p , q\) 均为奇数,故 \(2^x\) 必定为 \(1\) ,故 \(k1 = k2\)

证毕.

那么我们求 \(2^n * (2^n -1)* (...) * (2^n -m +1)\)\(2\) 因子个数(指数),相当于求 \((m-1)!\)\(2\) 约数个数

我们查询资料可以找到一个 \(O(log m)\) 的求解方法,即勒让德定理(Legendre's Theorem):

对于正整数\(n\)质数\(p\)\(n!\)中包含的\(p\)的幂次为:

\[v_p(n!) = \sum_{k=1}^{\infty} \left\lfloor \frac{n}{p^k} \right\rfloor \]

\(p=2\)时,计算\(n!\)中2的因子个数:

\[\text{CountOf2}(n!) = \left\lfloor \frac{n}{2} \right\rfloor + \left\lfloor \frac{n}{4} \right\rfloor + \left\lfloor \frac{n}{8} \right\rfloor + \cdots \]

\(\text{CountOf2}(n!)\)满足以下递推关系:

\[\text{CountOf2}(n!) = \begin{cases} 0 & \text{, } n < 2 \\ \left\lfloor \frac{n}{2} \right\rfloor + \text{CountOf2}\left(\left\lfloor \frac{n}{2} \right\rfloor\right) & \text{,}n \ge 2 \end{cases} \]

然后怎么算出分子先呢?总不能用 \(O(m)\) 的解法跑一遍累乘分子吧……还真可以,我们上面不是给出说明了吗,我们只需要处理 \(m \le mod\) 时的情况,不超过 \(10^6\)

那么分母约分直接在指数上减去就可以了,那分子如何执行除法呢?这就不得不提到费马小定理了:

\(p\)是一个质数,且\(a\)是一个与\(p\)互质的整数,则:

\[a^{p-1} \equiv 1 \pmod{p} \]

我们稍微变形一下:

\[a^{-1} \equiv a^{p-2} \pmod{p} \]

即在模 \(p\) 意义下 我们除去 \(a\) 等价于乘上 \(a^{p-2}\)

什么?你还怕指数储存爆掉 \(long long\)?,你这样写不就行了:

ll rtmp=qpow(qpow(2,tmp,mod),(mod-2),mod);

Code

#include<bits/stdc++.h> 
using std::cin;
using std::cout;
typedef long long ll;
const ll mod=1e6+3;
ll qpow(ll a,ll b,ll c){
	ll ret=1;
	while(b){
		if(b&1) ret=ret*a%c;
		a=a*a%c;
		b>>=1;
	}
	return ret;
}
ll f(ll x){
	return x?f(x/2)+x/2:0;
}
long long n,m;
ll tmp,cnt,cur,cel;
int main(){
	std::ios::sync_with_stdio(false);
	cin>>n>>m;
	tmp=f(m-1)+n;//2的因子
	ll rtmp=qpow(qpow(2,tmp,mod),(mod-2),mod);
	cnt=qpow(qpow(2,n,mod),m,mod)*rtmp%mod;//分母 
	if(m>=mod){
		cout<<(long long)cnt<<" "<<(long long)cnt;
		return 0;
	}
	cel=qpow(2,n,mod);
	cur=(qpow(2,n,mod)-(m%mod)+1+mod)%mod;
	for(ll i=1;i<m;i++){
		cur*=(cel-i+1);
		cur%=mod;
	}
	cur=(cur*rtmp)%mod;
	cout<<(long long)(cnt-cur+mod)%mod<<" "<<(long long)(cnt);
	return 0;
}
posted @ 2025-08-14 16:01  SSL_LMZ  阅读(9)  评论(0)    收藏  举报