[HNOI2017]抛硬币

Posted 蒟蒻ZJO :-)

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[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 补全。

输入输出样例

输入样例#1: 复制
2 1 9
3 2 1
输出样例#1: 复制
000000004
6

说明

对于第一组数据,当小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 91a,b1015,bab+10000,1k9,数据组数小于等于10。

 

 

习惯交换a,b.
先考虑ab都相等的情况.
每个硬币只有正反两种情况,所以在把一种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 }

 

 
























以上是关于[HNOI2017]抛硬币的主要内容,如果未能解决你的问题,请参考以下文章

刷题BZOJ 4830 [Hnoi2017]抛硬币

[HNOI2017]抛硬币

Excel:在 n 次抛硬币中出现 h 个正面的概率

用偏硬币模拟抛硬币的程序

概率DP 2017 ICPC 乌鲁木齐 A Coins

c_cpp 用计算机产生的伪随机数来模拟抛硬币试验。假设抛10次硬币,每次抛硬币得到正面和反面是随机的。抛10次硬币构成一个事件。调用随机(2)返回一个二值结果。在主程序中反复调用函数TossCoin