[HNOI2017]抛硬币
题目描述
小 A 和小 B 是一对好朋友,他们经常一起愉快的玩耍。最近小 B 沉迷于**师手游,天天刷本,根本无心搞学习。但是已经入坑了几个月,却一次都没有抽到 SSR,让他非常怀疑人生。勤勉的小 A 为了劝说小 B 早日脱坑,认真学习,决定以抛硬币的形式让小 B 明白他是一个彻彻底底的非洲人,从而对这个游戏绝望。两个人同时抛 b 次硬币,如果小 A 的正面朝上的次数大于小 B 正面朝上的次数,则小 A 获胜。
但事实上,小 A 也曾经沉迷过拉拉游戏,而且他一次 UR 也没有抽到过,所以他对于自己的运气也没有太大把握。所以他决定在小 B 没注意的时候作弊,悄悄地多抛几次硬币,当然,为了不让小 B 怀疑,他不会抛太多次。现在小 A 想问你,在多少种可能的情况下,他能够胜过小 B 呢?由于答案可能太大,所以你只需要输出答案在十进制表示下的最后 k 位即可。
输入输出格式
输入格式:有多组数据,对于每组数据输入三个数a,b,k,分别代表小A抛硬币的次数,小B抛硬币的次数,以及最终答案保留多少位整数。
输出格式:对于每组数据,输出一个数,表示最终答案的最后 k 位为多少,若不足 k 位以 0 补全。
输入输出样例
说明
对于第一组数据,当小A抛2次硬币,小B抛1次硬币时,共有4种方案使得小A正面朝上的次数比小B多。
(01,0), (10,0), (11,0), (11,1)
对于第二组数据,当小A抛3次硬币,小B抛2次硬币时,共有16种方案使得小A正面朝上的次数比小B多。
(001,00), (010,00), (100,00), (011,00), (101,00), (110,00), (111,00), (011,01), (101,01), (110,01),(111,01), (011,10), (101,10), (110,10), (111,10), (111,11).
数据范围
10%的数据满足a,b≤20;
30%的数据满足a,b≤100;
70%的数据满足a,b≤100000,其中有20%的数据满足a=b;
100%的数据满足1≤a,b≤1015,b≤a≤b+10000,1≤k≤91\le a,b\le 10^{15},b\le a\le b+10000,1\le k\le 91≤a,b≤1015,b≤a≤b+10000,1≤k≤9,数据组数小于等于10。
习惯交换a,b.
先考虑a和b都相等的情况.
每个硬币只有正反两种情况,所以在把一种B的获胜态翻转就会变成A的获胜态.
一共有2^(a+b)种情况.
那么答案为
平局的情况:
这个东西好像叫范德蒙德卷积.感性证明:
把2a均分为两组,那么从两组中一共取a个的方案数=分别从两组中取i个和a-i个的方案数.
现在讨论b>a的情况.
首先,a的获胜态翻转后必定是b的获胜态,但b的获胜态翻转不一定是a的获胜态.
若能够求出所有的b的获胜态且翻转时候还是b的获胜态的数量,记为S.
那么答案就是
现在只需求出S.
其中用到了范德蒙德卷积.
然后就用扩展Lucas算出来就可以了.
扩展Lucas:
用来求n!mod p^k.
可以把n!分为两类:
1.p的倍数,这些项提取p之后又是一个新的阶乘,递归处理即可.提取的p不要算进去,最后一起算.
2.其他项.可以发现,在模p^k的意义下,其他项会构成循环,最后不满的循环也不会超过p^k个,暴力搞就可以了.
1 #include<iostream> 2 #include<cstdio> 3 #include<cstdlib> 4 #include<cstring> 5 #include<string> 6 #include<algorithm> 7 #include<map> 8 #include<complex> 9 #include<queue> 10 #include<stack> 11 #include<cctype> 12 #include<cmath> 13 #include<set> 14 #include<vector> 15 #define RG register 16 #define mk make_pair 17 #define pb push_back 18 #define fi first 19 #define se second 20 #define UN unsigned 21 #define LL long long 22 using namespace std; 23 int pw[10]={1,10,100,1000,10000,100000,1000000,10000000,100000000,1000000000}; 24 int k,mod,p1,p2,jc[2][2000000]; 25 LL a,b; 26 bool flag=0; 27 inline void exgcd(RG LL aa,RG LL bb,RG LL &x,RG LL &y){ 28 if(bb==0) x=1,y=0; 29 else exgcd(bb,aa%bb,y,x),y-=(aa/bb)*x; 30 } 31 inline LL Inv(RG LL aa,RG LL p){ 32 LL x,y;exgcd(aa,p,x,y); 33 return (x+p)%p; 34 } 35 inline LL qpow(RG LL x,RG LL y,RG LL p){ 36 RG LL ans=1; 37 while(y){ 38 if(y&1) ans=ans*x%p; 39 y>>=1; 40 x=x*x%p; 41 } 42 return ans; 43 } 44 inline void prepare(){ 45 p1=1,p2=1; 46 for(RG int i=1;i<=k;i++) p1*=2,p2*=5; 47 jc[0][0]=jc[1][0]=1; 48 for(RG int i=1;i<=1999000;i++){ 49 if(i%2)jc[0][i]=(LL)jc[0][i-1]*i%p1;else jc[0][i]=jc[0][i-1]; 50 if(i%5)jc[1][i]=(LL)jc[1][i-1]*i%p2;else jc[1][i]=jc[1][i-1]; 51 } 52 } 53 inline LL Fac1(RG LL x){ 54 if(x==0) return 1; 55 RG LL re=jc[0][p1]; 56 re=qpow(re,x/p1,p1); 57 re=(re*jc[0][x%p1])%p1; 58 return re*Fac1(x/2)%p1; 59 } 60 inline LL Fac2(RG LL x){ 61 if(x==0) return 1; 62 RG LL re=jc[1][p2]; 63 re=qpow(re,x/p2,p2); 64 re=(re*jc[1][x%p2])%p2; 65 return re*Fac2(x/5)%p2; 66 } 67 inline LL calc1(RG LL n,RG LL m){ 68 if(n<m) return 0; 69 RG LL c=0; 70 for(RG LL i=n;i;i/=2) c+=i/2; 71 for(RG LL i=m;i;i/=2) c-=i/2; 72 for(RG LL i=n-m;i;i/=2) c-=i/2;if(flag) c--; 73 if(c>=k) return 0; 74 RG LL x=Fac1(n),y=Fac1(m),z=Fac1(n-m); 75 RG LL aa=(x*Inv(y,p1)%p1*Inv(z,p1)%p1)%p1*qpow(2,c,p1)%p1; 76 return (aa*(mod/p1)%mod*Inv(mod/p1,p1)%mod)%mod; 77 } 78 inline LL calc2(LL n,LL m){ 79 if(n<m) return 0; 80 RG LL c=0; 81 for(RG LL i=n;i;i/=5) c+=i/5; 82 for(RG LL i=m;i;i/=5) c-=i/5; 83 for(RG LL i=n-m;i;i/=5) c-=i/5; 84 if(c>=k) return 0; 85 RG LL x=Fac2(n),y=Fac2(m),z=Fac2(n-m); 86 RG LL aa=(x*Inv(y,p2)%p2*Inv(z,p2)%p2)%p2*qpow(5,c,p2)%p2; 87 if(flag) aa=aa*Inv(2,p2)%p2; 88 return (aa*(mod/p2)%mod*Inv(mod/p2,p2)%mod)%mod; 89 } 90 inline LL exlucas(RG LL n,RG LL m){ 91 RG LL a1=calc1(n,m),a2=calc2(n,m); 92 return (a1+a2)%mod; 93 } 94 int main(){ 95 freopen("!.in","r",stdin); 96 freopen("!.out","w",stdout); 97 while(scanf("%lld%lld%d",&a,&b,&k)!=EOF){ 98 swap(a,b);mod=pw[k]; 99 RG LL s=0;flag=0; 100 prepare(); 101 if(a!=b) for(RG LL i=a+1;i<=(a+b-1)/2;i++) s=(s+exlucas(a+b,i))%mod; 102 if((a+b)%2==0) flag=1,s=(s+exlucas(a+b,(a+b)/2))%mod; 103 if(a==b) s=(mod-s)%mod; 104 RG LL ans=(qpow(2,a+b-1,mod)+s)%mod; 105 for(RG int i=k-1;i>=0;i--) 106 printf("%d",ans/pw[i]),ans%=pw[i]; 107 printf("\n"); 108 } 109 return 0; 110 }