题意:给出2^n天,k个人,求至少有两个人同一天过生日的概率
题解:首先k>2^n 概率为1 判掉
至少有两个人同一天的概率 等价于 1-都不是一天的概率
1-(2^n-1)/(2^n)....(2^n-k+1)/(2^n)
gcd(a,b)=gcd(b-a,b) b>a
所以gcd(2^n-t,2^n)=gcd(t,2^n)
(a-b)%m=(a%m-b%m)+m%m a>b
所以根据这个公式 只要(2^n-i)中有一个是1000003的倍数就为0
如果没有的话 gcd(2^n-i,2^n)=gcd(i,2^n) 只要算出来每个i与2^n的公因子即可 因为分母只有2 所以只用找2就行了 记因子为t个2
有一个快速算的方法是 while(k/2)t+=k/2 k/=2 这样算的原理是 第一次算出k中有多少个是2的倍数 然后全体缩小1倍 循环下去
算出来分母 分母就是2^(nk)/(2^t) 等于 2^(nk)*inv(2^t)
分子就等于 分母-(2^n-1)*...*(2^n-k+1)*inv(2^t)
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;
typedef long long ll;
const ll mod=1000003;
ll a[70];
ll quick(ll a,ll k){//a^k%m 快速幂
ll ans=1;
while(k){
if(k&1)ans=ans*a%mod;
k/=2;
a=a*a%mod;
}
return ans;
}
int main(){
ll n,k,i;
cin>>n>>k;
a[0]=1;
for(i=1;i<=63;i++)a[i]=a[i-1]*2;
if(n<=63&&k>=a[n]+1){//如果k>2^n
printf("1 1\n");
return 0;
}
ll t=0,now;
now=k-1;
while(now>1){//计算t
t+=now/2;
now/=2;
}
ll mu;
mu=quick(quick(2,n),k-1);//2^(n*k)
mu=mu*quick(quick(2,t),mod-2)%mod;// inv(2^t)
ll zi;
zi=mu;//开始时候分子等于前面的 2^(n*k)/(2^t)
ll s=1;
for(i=-k+1;i<=-1;i++){
if((-1+k)>=1000006){//如果这个区间有1000003的倍数 直接就为0
s=0;
break;
}
if(((quick(2,n)+i)%mod+mod)%mod==0){//算出当前的2^n+i mod m是否为0
s=0;
break;
}
s=s*((quick(2,n)+i)%mod+mod)%mod;//s=s*(2^n+i)
}
s=s*quick(quick(2,t),mod-2)%mod;//s=s/(2^t)
zi=((zi-s)%mod+mod)%mod;//zi=zi-s
printf("%lld %lld\n",zi,mu);
return 0;
}