Description
小A和小B抛硬币,小A抛了A次,小B抛了B次(有顺序)
现在小A想知道,有多少种情况,小A正面朝上的次数比小B多
答案保留十进制下最后K位
10组数据
B≤A≤B+10000,K≤9
Solution
分情况考虑
如果A=B
可以发现小A赢和小B赢的情况数是一样的
平局的次数是
∑i=1ACiACiB=CAA+B
那么答案就是 2A+B−CAA+B2
如果A>B
将两个人抛硬币的结果用二进制状态表示,1表示正面朝上
如果小A没赢,那么将这个状态二进制翻转,得到的结果一定是小A赢的
所以我们只需要求出一个值S,表示有多少种情况是小A赢,且翻转过来还是小A赢
答案就是
2A+B+S2
设小A抛正面朝上x次,小B正面朝上y次
那么
x>y
且
A−x>B−y
化一下就是
0<x−y<A−B
同时x<=A,y<=B
设d=x-y
那么
S=∑d=1A−B−1∑y=0BCy+dACyB
=∑d=1A−B−1∑y=0BCy+dACB−yB
根据组合恒等式,可以化成下面
=∑d=1A−B−1CB+dA+B
这个就随便做了,剩下的就是组合数取模的问题了
Code
惨遭卡常
可能是我组合数取模写丑了?
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <iostream>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define fod(i,a,b) for(int i=a;i>=b;i--)
#define LL long long
#define N 10000001
#define M 1000001
using namespace std;
LL mo,cf[11],lim,m1,m2,ny1,ny2;
int js2[N],js5[N],num2[M],num5[M],sum2[M],sum5[M];
LL kst(LL x,LL y,LL mo)
{
if(!x||!y) return 0;
if(y==1) return x;
if(x<=1e9&&y<=1e9) return x*y%mo;
LL s=kst(x,y/2,mo);
return(y&1)?(s+s+x)%mo:(s+s)%mo;
}
LL ksm(LL k,LL n,LL mo)
{
if(k==0) return 0;
if(k==1) return 1;
k%=mo;
LL s=1;
for(;n;n>>=1,k=kst(k,k,mo))
{
if(k==1) return s;
if(n&1) s=kst(s,k,mo)%mo;
}
return s;
}
LL ks(LL k,LL n,LL mo)
{
if(k==0) return 0;
if(k==1) return 1;
k%=mo;
LL s=1;
for(;n;n>>=1,k=k*k%mo)
{
if(k==1) return s;
if(n&1) s=s*k%mo;
}
return s;
}
LL js(LL n,LL p,LL &v,LL mo)
{
if(n<=M-1)
{
if(p==2)
{
v=num2[n];
return sum2[n];
}
else
{
v=num5[n];
return sum5[n];
}
}
if(n==0)
{
v=0;
return 1;
}
LL s1,v1;
s1=js(n/p,p,v1,mo);
v=v1+n/p;
if(p==2) return s1*ks(js2[mo]%mo,n/mo,mo)%mo*(js2[n%mo]%mo)%mo;
else return s1*ks(js5[mo]%mo,n/mo,mo)%mo*(js5[n%mo]%mo)%mo;
}
void exgcd(LL a,LL b,LL &x,LL &y)
{
if(b==0) x=1,y=0;
else
{
exgcd(b,a%b,x,y);
LL p=x;
x=y,y=p-(a/b)*y;
}
}
LL ny(LL k,LL mo)
{
LL a=k,b=mo,x,y;
exgcd(a,b,x,y);
return (x+mo)%mo;
}
LL doit(LL n,LL m,LL pr,LL mo)
{
LL s1,p,s2,q,s3,v;
s1=js(n,pr,p,mo);
s2=js(m,pr,q,mo);
s3=js(n-m,pr,v,mo);
p-=q+v;
if(p>=lim) return 0;
return s1*ny(s2,mo)%mo*ny(s3,mo)%mo*ks(pr,p,mo)%mo;
}
LL C(LL m,LL n)
{
if(m>n) return 0;
LL sx=doit(n,m,2,m1),sy=doit(n,m,5,m2);
return (sx*m2%mo*ny1%mo+sy*m1%mo*ny2%mo)%mo;
}
LL sum(LL a,LL b)
{
LL s=0;
fo(i,1,a-b-1) (s+=C(b+i,a+b))%=mo;
return s;
}
int main()
{
cf[0]=1;
fo(i,1,10) cf[i]=cf[i-1]*(LL)10;
LL a,b;
m1=ksm(2,10,cf[10]),m2=ksm(5,10,cf[10]);
js2[0]=js5[0]=1;
fo(i,1,N-1)
{
js2[i]=js2[i-1],js5[i]=js5[i-1];
if(i%2!=0) js2[i]=(LL)js2[i]*(LL)i%m1;
if(i%5!=0) js5[i]=(LL)js5[i]*(LL)i%m2;
}
sum2[0]=sum5[0]=1;
fo(i,1,M-1)
{
num2[i]=num2[i-1],num5[i]=num5[i-1],sum2[i]=sum2[i-1],sum5[i]=sum5[i-1];
LL i1=i;
while(i1%2==0) num2[i]++,i1>>=1;
sum2[i]=sum2[i]*i1%m1;
i1=i;
while(i1%5==0) num5[i]++,i1/=5;
sum5[i]=sum5[i]*i1%m2;
}
while(scanf("%lld%lld%d",&a,&b,&lim)!=EOF)
{
mo=cf[lim];
mo=mo*(LL)10;
lim++;
m1=ksm(2,lim,mo),m2=ksm(5,lim,mo);
ny1=ny(m2,m1),ny2=ny(m1,m2);
LL ans;
if(a==b) ans=(ksm(2,a+b,mo)-C(a,a+b)+mo)%mo/2;
else ans=(ksm(2,a+b,mo)+sum(a,b))%mo/2;
ans=ans%(mo/10);
fod(i,lim-2,1) if(ans<cf[i]) printf("0");
printf("%lld\n",ans);
}
}