Description
小A和小B是一对好朋友,他们经常一起愉快的玩耍。最近小B沉迷于**师手游,天天刷本,根本无心搞学习。但是
已经入坑了几个月,却一次都没有抽到SSR,让他非常怀疑人生。勤勉的小A为了劝说小B早日脱坑,认真学习,决
定以抛硬币的形式让小B明白他是一个彻彻底底的非洲人,从而对这个游戏绝望。两个人同时抛b次硬币,如果小A
的正面朝上的次数大于小B正面朝上的次数,则小A获胜。但事实上,小A也曾经沉迷过拉拉游戏,而且他一次UR也
没有抽到过,所以他对于自己的运气也没有太大把握。所以他决定在小B没注意的时候作弊,悄悄地多抛几次硬币
,当然,为了不让小B怀疑,他不会抛太多次。现在小A想问你,在多少种可能的情况下,他能够胜过小B呢?由于
答案可能太大,所以你只需要输出答案在十进制表示下的最后k位即可。
Input
有多组数据,对于每组数据输入三个数a,b,k,分别代表小A抛硬币的次数,小B抛硬币的次 数,以及最终答案保留多少位整数。
1≤a,b≤10^15,b≤a≤b+10000,1≤k≤9,数据组数小于等于10。
Output
对于每组数据,输出一个数,表示最终答案的最后k位为多少,若不足k位以0补全。
Sample Input
2 1 9
3 2 1
Sample Output
000000004
6
HINT
【样例解释】
对于第一组数据,当小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)
题解
思路还是非常神仙的…
不妨把抛硬币的操作看成01序列
先从A=B开始考虑
01接起来,显然是个2*A的序列
这时候每个A赢的方案都对应了一个01反转之后B赢的方案
我们需要去掉的就只有A和B平手的方案
就是∑CAi∗CBi\sum C_{A}^{i}*C_{B}^{i}∑CAi∗CBi,换一下就是∑CAiCBB−i\sum C_{A}^{i}C_{B}^{B-i}∑CAiCBB−i
就是2*A的前A个选i个,后A个选A-i个,那么就是
2A+B−C2AA2\frac{2^{A+B}-C_{2A}^{A}}{2}22A+B−C2AA
拓展到A≠BA\neq BA̸=B
在某些A赢的情况下01反转后仍然还可以做到是B赢
然而B赢的情况01反转后一定是A赢的方案
那其实去掉的是A赢反转后仍然是A赢的方案
枚举一个B是1的数量i,再枚举A比他多的j
于是就要满足不等式A−(i+j)>B−iA-(i+j)>B-iA−(i+j)>B−i
移项可知j<=A−B−1j<=A-B-1j<=A−B−1
不合法的方案数就是∑i=0BCBi∗∑j=1a−b−1CAi+j\sum_{i=0}^{B}C_{B}^i*\sum_{j=1}^{a-b-1}C_{A}^{i+j}∑i=0BCBi∗∑j=1a−b−1CAi+j
变一下就是∑i=0BCBB−i∗∑j=1a−b−1CAi+j\sum_{i=0}^{B}C_{B}^{B-i}*\sum_{j=1}^{a-b-1}C_{A}^{i+j}∑i=0BCBB−i∗∑j=1a−b−1CAi+j
这个柿子实际上等价于前B个选择了B-i个1,后A个选择了i+j个1
那么就是∑j=1A+B−1CA+BB+j\sum_{j=1}^{A+B-1} C_{A+B}^{B+j}∑j=1A+B−1CA+BB+j,可以知道这种状态下的答案是
2A+B+∑j=1A+B−1CA+BB+j2\frac{2^{A+B}+\sum_{j=1}^{A+B-1}C_{A+B}^{B+j}}{2}22A+B+∑j=1A+B−1CA+BB+j
扩展lucas玩玩
然后就到了卡常阶段
发现模数的质因子固定,可以先把阶乘预处理
然后根据杨辉三角 组合数只用算一半
然后就可以了…
其实卡了一早上
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<queue>
#include<vector>
#include<ctime>
#include<map>
#include<bitset>
#define LL long long
#define mp(x,y) make_pair(x,y)
#define pll pair<long long,long long>
#define pii pair<int,int>
using namespace std;
inline LL read()
{
LL f=1,x=0;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
int stack[20];
inline void write(int x)
{
if(x<0){putchar('-');x=-x;}
if(!x){putchar('0');return;}
int top=0;
while(x)stack[++top]=x%10,x/=10;
while(top)putchar(stack[top--]+'0');
}
inline void pr1(int x){write(x);putchar(' ');}
inline void pr2(int x){write(x);putchar('\n');}
int f1[3100000],f2[3100000];
void init(int md1,int md2)
{
f1[0]=f2[0]=1;
for(int i=1;i<=md1;i++)f1[i]=(LL)f1[i-1]*((i%2)?i:1)%md1;
for(int i=1;i<=md2;i++)f2[i]=(LL)f2[i-1]*((i%5)?i:1)%md2;
}
int pow_mod(int a,LL b,int mod)
{
int ret=1;
while(b)
{
if(b&1)ret=(LL)ret*a%mod;
a=(LL)a*a%mod;b>>=1;
}
return ret;
}
int exgcd(int a,int b,int &x,int &y)
{
if(a==0)
{
x=0;y=1;
return b;
}
else
{
int tx,ty;
int d=exgcd(b%a,a,tx,ty);
x=ty-(b/a)*tx;
y=tx;
return d;
}
}
int getinv(int a,int mod)
{
int AA=a,BB=mod,K=1,x,y;
int d=exgcd(AA,BB,x,y);
x=((LL)x*(K/d)%(BB/d)+(BB/d))%(BB/d);
return x;
}
int solve(LL n,int pi,int mod)
{
if(!n)return 1;
int ret=1;
if(pi==2)ret=(LL)ret*f1[mod]%mod;
else ret=(LL)ret*f2[mod]%mod;
ret=pow_mod(ret,n/mod,mod);
if(pi==2)ret=(LL)ret*f1[n%mod]%mod;
else ret=(LL)ret*f2[n%mod]%mod;
return (LL)ret*solve(n/pi,pi,mod)%mod;
}
int lim;
int exlucas(LL n,LL m,int pi,int mod,bool tf)
{
int ok=0;
for(LL i=n;i;i/=pi)ok+=i/pi;
for(LL i=m;i;i/=pi)ok-=i/pi;
for(LL i=n-m;i;i/=pi)ok-=i/pi;
if(tf&&pi==2)ok--;
if(ok>=lim)return 0;
int a=solve(n,pi,mod),b=solve(m,pi,mod),c=solve(n-m,pi,mod);
return (LL)a*getinv(b,mod)%mod*getinv(c,mod)%mod*pow_mod(pi,ok,mod)%mod;
}
LL p1[5];
int C(LL n,LL m,int mod,bool tf)
{
if(n<m)return 0;
p1[1]=p1[2]=1;
while(!(mod%2)&&mod)p1[1]*=2,mod/=2;
while(!(mod%5)&&mod)p1[2]*=5,mod/=5;
int b1=exlucas(n,m,2,p1[1],tf),m1=p1[1];
int b2=exlucas(n,m,5,p1[2],tf),m2=p1[2];
if(tf)b2=(LL)b2*getinv(2,p1[2])%p1[2];
int A=m1,B=m2,K=b2-b1,x,y;
int d=exgcd(A,B,x,y);
x=((LL)x*(K/d)%(B/d)+(B/d))%(B/d);
return ((LL)m1*x+b1)%(p1[1]*p1[2]);
}
LL A,B,K;
void ot(LL u,int k)
{
int ret=0,g=u;
while(g)ret++,g/=10;
for(int i=1;i<=k-ret;i++)putchar('0');
pr2(u);
}
int main()
{
init(512,1953125);
while(scanf("%lld%lld%lld",&A,&B,&K)!=EOF)
{
LL o=1,n1=1,n2=1,cnt=0;lim=K;
while(cnt+1<=K)o*=10,n1*=2,n2*=5,cnt++;
swap(o,K);
if(A==B)
{
int temp=pow_mod(2,A+B-1,K);
temp=(temp-C(2*A,A,K,1)+K)%K;
ot(temp,o);
}
else
{
int temp=pow_mod(2,A+B-1,K);
if(!((A+B)&1))
{
temp+=C(A+B,(A+B)/2,K,1);
if(temp>=K)temp-=K;
}
for(LL i=(A+B)/2+1;i<=A-1;++i)
{
temp+=C(A+B,i,K,0);
if(temp>=K)temp-=K;
}
ot(temp,o);
}
}
return 0;
}

本文探讨了一种基于抛硬币次数的策略游戏,通过数学分析和编程实现,计算了在特定条件下玩家A战胜玩家B的概率,尤其是在玩家A通过作弊手段增加胜利机会的情景下。文章详细介绍了使用组合数学原理解决这一问题的方法。
1万+

被折叠的 条评论
为什么被折叠?



