[AH/HNOI2017]抛硬币
Posted Z-Y-Y-S
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[AH/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\\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。
转载http://www.cnblogs.com/Yuzao/p/7954245.html
因为 \\(a-b\\) 很小,考虑怎么把式子变成和 \\(a-b\\) 有关.
考虑 \\(a=b\\) 的情况,赢了翻转后就输了,平局不算在内,
要减掉的。减了之后再除。推导如下:
$$\\sum_{i=0}^{a}C_a^i * C_a^i = \\sum_{i=0}^{a}C_a^i * C_a^{a-i} = C_{2a}^a$$
平局方案为C(2a,a)
所以答案为 \\((2^{a+b}-C(2a,a))/2\\).
\\(a>b\\) 时,同样存在对称性,对于正着会输,反过来就赢得情况,就是 \\(2^{a+b}/2\\) 种
对于正着反着都赢的情况还没有算进去:
\\[\\sum_{i=1}^{b}\\sum_{j=1}^{a-b-1}C_{b}^{i}*C_{a}^{i+j}\\]
\\[\\sum_{i=1}^{b}\\sum_{j=1}^{a-b-1}C_{b}^{b-i}*C_{a}^{i+j}\\]
\\[\\sum_{j=1}^{a-b-1}C_{a+b}^{b+j}\\]
\\[\\sum_{j=b+1}^{a-1}C_{a+b}^{j}\\]
对于除2,根据对称性,只算一半即可,注意偶数情况,存在一项需要手动除2,算2时在因子中减去,算5时直接乘逆元即可
取模不是素数,所以要中国剩余定理
可以默认模数为10^9,输出时取模
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 using namespace std; 6 typedef long long ll; 7 ll K,fac[6][2000001]; 8 ll exgcd(ll a,ll b,ll &x,ll &y) 9 { 10 if (b==0) 11 { 12 x=1;y=0; 13 return a; 14 } 15 ll d=exgcd(b,a%b,x,y); 16 ll t=x;x=y;y=t-(a/b)*x; 17 return d; 18 } 19 ll qpow(ll a,ll b,ll mod) 20 { 21 ll res=1; 22 while (b) 23 { 24 if (b&1) res=res*a%mod; 25 a=a*a%mod; 26 b/=2; 27 } 28 return res; 29 } 30 ll rev(ll a,ll b) 31 { 32 ll x,y; 33 exgcd(a,b,x,y); 34 return (x%b+b)%b; 35 } 36 ll calfac(ll x,ll p,ll t) 37 { 38 if (x<t) return fac[t][x]; 39 ll s=qpow(fac[t][p-1],x/p,p); 40 s=(s*fac[t][x%p])%p; 41 s=(s*calfac(x/t,p,t))%p; 42 return s; 43 } 44 ll lucas(ll b,ll a,ll t,ll p,bool q) 45 {ll i; 46 if (b<a) return 0; 47 ll ap=0,bp=0,cp=0; 48 for (i=b;i;i/=t) ap+=i/t; 49 for (i=a;i;i/=t) bp+=i/t; 50 for (i=b-a;i;i/=t) cp+=i/t; 51 ap=ap-bp-cp; 52 if (q==1&&t==2) ap--; 53 if (ap>=K) return 0; 54 ll s=qpow(t,ap,p); 55 ap=calfac(b,p,t);bp=calfac(a,p,t),cp=calfac(b-a,p,t); 56 s=((s*ap%p)*(rev(bp,p)*rev(cp,p))%p)%p; 57 if (q&&t==5) s=s*rev(2,p)%p; 58 return s; 59 } 60 ll cal(ll a,ll b,ll Mod,ll pr) 61 {ll i; 62 ll ans=qpow(2,a+b-1,Mod); 63 if (a==b) 64 { 65 ans=(ans-lucas(a+b,a,pr,Mod,1)+Mod)%Mod; 66 return ans; 67 } 68 else 69 { 70 for (i=(a+b)/2+1;i<a;i++) 71 ans=(ans+lucas(a+b,i,pr,Mod,0)+Mod)%Mod; 72 } 73 if ((a+b)%2==0) ans=(ans+lucas(a+b,(a+b)/2,pr,Mod,1)+Mod)%Mod; 74 return ans; 75 } 76 ll work(ll a,ll b,ll k) 77 { 78 ll p1=qpow(2,k,2e9+5),p2=qpow(5,k,2e9+5),mod=qpow(10,k,2e9+5); 79 ll b1=cal(a,b,p1,2),b2=cal(a,b,p2,5); 80 ll a1=rev(p2,p1),a2=rev(p1,p2); 81 return (b1*(p2*a1%mod)%mod+b2*(p1*a2%mod)%mod)%mod; 82 } 83 void print(ll d,ll k) 84 { 85 if (k==1) 86 printf("%01lld\\n",d%qpow(10,1,2e9+5)); 87 if (k==2) 88 printf("%02lld\\n",d%qpow(10,2,2e9+5)); 89 if (k==3) 90 printf("%03lld\\n",d%qpow(10,3,2e9+5)); 91 if (k==4) 92 printf("%04lld\\n",d%qpow(10,4,2e9+5)); 93 if (k==5) 94 printf("%05lld\\n",d%qpow(10,5,2e9+5)); 95 if (k==6) 96 printf("%06lld\\n",d%qpow(10,6,2e9+5)); 97 if (k==7) 98 printf("%07lld\\n",d%qpow(10,7,2e9+5)); 99 if (k==8) 100 printf("%08lld\\n",d%qpow(10,8,2e9+5)); 101 if (k==9) 102 printf("%09lld\\n",d%qpow(10,9,2e9+5)); 103 } 104 int main() 105 {ll a,b,k,i,p; 106 fac[2][0]=1;p=qpow(2,9,2e9+5); 107 for (i=1;i<=p-1;i++) 108 if (i%2==0) fac[2][i]=fac[2][i-1]; 109 else fac[2][i]=fac[2][i-1]*i%p; 110 fac[5][0]=1;p=qpow(5,9,2e9+5); 111 for (i=1;i<=p-1;i++) 112 if (i%5==0) fac[5][i]=fac[5][i-1]; 113 else fac[5][i]=fac[5][i-1]*i%p; 114 while (cin>>a>>b>>k) 115 { 116 K=9;ll d=work(a,b,9); 117 print(d,k); 118 } 119 }
以上是关于[AH/HNOI2017]抛硬币的主要内容,如果未能解决你的问题,请参考以下文章