1. 程式人生 > >[AH/HNOI2017]拋硬幣

[AH/HNOI2017]拋硬幣

ret class otto htm 沒有 由於 逆元 radius 輸入

題目描述

小 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\le a,b\le 10^{15},b\le a\le b+10000,1\le k\le 91a,b1015,bab+10000,1k9,數據組數小於等於10。

暫時轉載http://www.cnblogs.com/Yuzao/p/7954245.html

因為 \(a-b\) 很小,考慮怎麽把式子變成和 \(a-b\) 有關.
考慮 \(a=b\) 的情況,考慮結果只有輸贏和平局三種,而且輸贏是對稱的,所以減去平局就是答案,所以答案為 \((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時直接乘逆元即可

  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]拋硬幣