[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 补全。

输入输出样例

输入样例#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 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\) 的情况,考虑结果只有输赢和平局三种,而且输赢是对称的,所以减去平局就是答案,所以答案为 \((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 }
时间: 2024-10-10 04:34:06

[AH/HNOI2017]抛硬币的相关文章

【刷题】BZOJ 4830 [Hnoi2017]抛硬币

Description 小A和小B是一对好朋友,他们经常一起愉快的玩耍.最近小B沉迷于**师手游,天天刷本,根本无心搞学习.但是已经入坑了几个月,却一次都没有抽到SSR,让他非常怀疑人生.勤勉的小A为了劝说小B早日脱坑,认真学习,决定以抛硬币的形式让小B明白他是一个彻彻底底的非洲人,从而对这个游戏绝望.两个人同时抛b次硬币,如果小A的正面朝上的次数大于小B正面朝上的次数,则小A获胜.但事实上,小A也曾经沉迷过拉拉游戏,而且他一次UR也没有抽到过,所以他对于自己的运气也没有太大把握.所以他决定在小

[HNOI2017]抛硬币

标签:扩展卢卡斯+方案数推导.题解: 首先要想到使用组合数而不是DP,否则就会深陷泥潭而不可自拔了. 我们把两个序列拼起来,也就是a+b个位置,每一个位置都是0或1.自然有2^(a+b)种方案.我们分a==b和a>b两种情况来讨论(我也不知道怎么想到这两种情况是不一样的): a==b:首先a的赢和输是对称的,如果b赢,反过来就是一种a赢的方案,当然在2^(a+b)种方案中,自然也会有这一种赢的方案,所以相当于÷2即可.但是还有平局的情况,记为S,是要减掉的.减了之后再除.推导如下: $$\sum

抛硬币的两种思维方式

抛硬币是经典统计学中最基础的案例,无论是理论还是实验,都证明了50%这个概率,而且抛的次数越多,越接近这个值. 我们来看看一下这个问答:(以下对话例子来源于塔勒布的<黑天鹅>) A:假设硬币是公平的,因为每次抛出硬币得到正面与反面的可能性都是相同的.我把它抛出了99次,每次都正好得到正面.那么,我下一次得到反面的概率是多大? 回答者1(统计学家):毫无疑问,当然是50%,因为统计学中的样本独立性,不管你前面得到了什么结果,与下一次的结果都无关,所以可能性依然是50%. 好吧,对于学过统计的人,

csu 1009 抛硬币

C - 抛硬币 CSU - 1009 James得到了一堆有趣的硬币,于是决定用这些硬币跟朋友们玩个小游戏.在一个N行M列的表格上,每一个第i行第j列的格子上都放有一枚James的硬币,抛该硬币正面朝上的概率为Pij,所有抛硬币事件两两之间是相互独立的. 现在,玩家在M列硬币中,从每一列里各选择1枚,共M枚,构成一组.如此重复选择N组出来,且保证被选择过的硬币不能再选.选好组之后,每组的M枚硬币各抛一次,如果都是正面朝上,则该组胜利,总分赢得1分:否则该组失败,总分不加也不减.请问,如果让你自行

模拟抛硬币(C语言实现)

实现代码: 1 #include<stdio.h> 2 #include<stdlib.h> 3 4 int heads() 5 { 6 return rand() < RAND_MAX/2; 7 } 8 9 int main(int argc, char *argv[]) 10 { 11 int i,j,cnt; 12 int N = atoi(argv[1]), M = atoi(argv[2]); 13 int *f = malloc((N+1)*sizeof(int)

抛硬币 Flipping Coins(Gym - 101606F)

Here's a jolly and simple game: line up a row of N identical coins, all with the heads facing down onto the table and the tails upwards, and for exactly K times take one of the coins, toss it into the air, and replace it as it lands either heads-up o

抛硬币问题

每次抛掷硬币正面向上和反面向上的概率是相同的 问题 1 :抛掷硬币 n 次,求连续 k 次正面向上的方案数有多少种 ? 一个比较好想的点子是直接 2^n 枚举,在这其中寻找符合要求的有多少种,复杂度爆表... 在计算连续 k 次正面向上的方案数可能并不太好算,那么就转换成 用总的方案数减去仅有连续小于 k 次的方案数 dp[i] 表示 到第 i 个位置仅存在小于连续 k 次正面向上的方案数 1 . 当 i < k 时, dp[i] = dp[i-1]*2 2 . 当 i == k 时, dp[i

用随机数列模拟抛硬币

先粘贴上代码 package djbc; import java.util.Random;import java.util.Scanner; public class Lian {public static void main(String[] args) {int i=0,k=0,t=0;  System.out.println("请输入要抛的次数");Scanner scan=new Scanner(System.in);//输入抛硬币的次数t=scan.nextInt();Ran

HZOI20190908模拟40 队长快跑,影魔,抛硬币 题解

题面:https://www.cnblogs.com/Juve/articles/11487699.html 队长快跑: 权值线段树与dp yy的不错 #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<cmath> using namespace std; const int MAXN=1e5+5; int n,a[MAXN],b[