您的位置:首页 > 其它

CodeForces 711E ZS and The Birthday Paradox

2016-08-31 17:09 375 查看
抽屉原理,快速幂,逆元,概率。

如果$k > {2^n}$,根据抽屉原理可知,答案就是$1$ $1$。

否则概率一定小于$1$,就要计算,公式很简单,上过概率论的应该都会算。

概率为:$1 - \frac{{({2^n} - 0)*({2^n} - 1)*({2^n} - 2)*({2^n} - 3)*......*({2^n} - (k - 1))}}{{{2^{nk}}}}$ $ = 1 - \frac{{({2^n} - 1)*({2^n} - 2)*({2^n} - 3)*......*({2^n} - (k - 1))}}{{{2^{n(k - 1)}}}}$。

下面我们来计算这一部分:$\frac{{({2^n} - 1)*({2^n} - 2)*({2^n} - 3)*......*({2^n} - (k - 1))}}{{{2^{n(k - 1)}}}}$。

因为分母是$2$的幂次,所以分子和分母的$GCD$肯定是$2$的幂次。设$GCD={2^{tmp}}$。$tmp$的求法很简单,就是$1,2,3,4,5,...,k-1$这些数能被$2$整除的次数之和。

然后我们要将分子分母同时除以${2^{tmp}}$,可以转化为$×{2^{tmp}}$的逆元。

这个时候又遇到了一个难题:分子的项这么多,怎么求?

仔细思考一下会发现,分子是连续的$k-1$个数字相乘,如果$k-1>=mod$,根据抽屉原理可知,分子中必然有一个数字是$mod$的倍数。

也就是说,如果$k-1>=mod$,那么分子取模之后就是$0$;如果$k-1<mod$,那么暴力循环一遍算出分子就可以了。

#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<vector>
#include<map>
#include<set>
#include<queue>
#include<stack>
#include<iostream>
using namespace std;
typedef long long LL;
const double pi=acos(-1.0),eps=1e-8;
void File()
{
freopen("D:\\in.txt","r",stdin);
freopen("D:\\out.txt","w",stdout);
}
template <class T>
inline void read(T &x)
{
char c = getchar(); x = 0;while(!isdigit(c)) c = getchar();
while(isdigit(c)) { x = x * 10 + c - '0'; c = getchar();  }
}

LL mod=1e6+3,pmod=mod-1;
LL n,k;

LL extend_gcd(LL a,LL b,LL &x,LL &y)
{
if(a==0&&b==0) return -1;
if(b==0){x=1;y=0;return a;}
LL d=extend_gcd(b,a%b,y,x);
y-=a/b*x;
return d;
}

LL mod_reverse(LL a,LL p)
{
LL x,y;
LL d=extend_gcd(a,p,x,y);
if(d==1) return (x%p+p)%p;
else return -1;
}

LL POW(LL a, LL b)
{
LL ans = 1; a %= mod;
while(b)
{
if(b & 1) ans = ans * a % mod, b--;
b >>= 1; a = a * a % mod;
}
return ans;
}

int main()
{
scanf("%lld%lld",&n,&k);
LL u=1; bool flag=0;
for(LL i=1;i<=n;i++)
{
u=u*(LL)2;
if(k<=u) { flag=1; break; }
}
if(flag==0) printf("1 1\n");
else
{
LL fz,fm;
LL h=(n%pmod)*(((k%pmod)-1+pmod)%pmod)%pmod+pmod;
fm=POW((LL)2,h);
LL tmp=0; for(LL i=2;i<=k-1;i=i*2) tmp=tmp+(k-1)/i;
LL GCD=POW((LL)2,tmp);
LL NI=mod_reverse(GCD,mod);
fm=fm*NI%mod;
if(k-1>=mod) printf("%lld %lld\n",fm,fm);
else
{
fz=1; for(LL i=1;i<=k-1;i++) fz=fz*((POW((LL)2,n)-i+mod)%mod)%mod;
fz=fz*NI%mod;
fz=(fm-fz+mod)%mod;
printf("%lld %lld\n",fz,fm);
}
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: