AtCoder m_solutions2019_c

这是 2019.6.1 hb 邀请 dreamoon 来的时候,全体陪他打的比赛的 C 题。当时比赛结束之后列了一个无穷级数,当时不会解无穷级数,就弃了。几个月后某天早上刷牙的时候突然想起来这玩意好像可以错位相减然后降幂!这样复杂度就是线性了!然后又鸽了好几个月心血来潮写了一发,发现太难写了就有弃了……一只鸽到现在。本来想今年 6.1 A 掉它的,结果昨天做了一个概率期望题,就顺便把这题做掉了。


首先有这个平局这个东西存在,使得次数可能达到无限。我们不列无穷级数,想办法把这个平局给搞掉。我们可以重新定义「一次」为从当前开始第一次分出胜负,这样次数显然是有限的,就很好求。而这两者的转化恰好是成比例的,原定义下的答案显然是新定义下的答案乘以「新的一次在原定义下的期望次数」,而这显然是个定值。设它为 (e),显然满足 (e=1+Ce),所以 (e=dfrac{1}{1-C})(这个 (e) 其实也能列无穷级数求)。

然后考虑新问题的答案。那次数显然少则 (n),多则 (2n-1),枚举一下,考虑每种的概率是多少。假设 A 赢了,最后一步显然一定要是 A,前面要有 (n-1) 个 A 和 (i-n) 个 B,总分布方式数是 (dbinom{i-1}{n-1})。而每种出现的概率为 (A^nB^{i-n})(注意这时候 (A,B) 就是原 (A,B) 的相对概率,即保持比例不变且 (A+B=1))。B 赢的话就镜像一波,容易列出 (i) 次的概率。然后乘以 (ie) 加起来就是答案的期望值啦。

代码就不用给了吧 qwq

算了放个代码纪念一下吧(

#include<bits/stdc++.h>
using namespace std;
const int mod=1000000007;
const int N=200000;
int qpow(int x,int y){
	int res=1;
	while(y){
		if(y&1)res=1ll*res*x%mod;
		x=1ll*x*x%mod;
		y>>=1;
	}
	return res;
}
int inv(int x){return qpow(x,mod-2);}
int n,A,B,C;
int fact[N+1],factinv[N+1];
int comb(int x,int y){return 1ll*fact[x]*factinv[y]%mod*factinv[x-y]%mod;}
int main(){
	cin>>n>>A>>B>>C;
	A=1ll*A*inv(100)%mod,B=1ll*B*inv(100)%mod,C=1ll*C*inv(100)%mod;
	fact[0]=factinv[0]=1;
	for(int i=1;i<=2*n;i++)factinv[i]=inv(fact[i]=1ll*fact[i-1]*i%mod);
	int e=inv(1-C),ans=0;
	A=1ll*A*e%mod,B=1ll*B*e%mod;
	for(int i=n;i<2*n;i++){
		(ans+=1ll*comb(i-1,n-1)*((1ll*qpow(A,n)*qpow(B,i-n)+1ll*qpow(B,n)*qpow(A,i-n))%mod)%mod*i%mod*e%mod)%=mod;
	}
	cout<<(ans+mod)%mod;
	return 0;
}
珍爱生命,远离抄袭!
原文地址:https://www.cnblogs.com/ycx-akioi/p/solution-atc-m_solutions2019_c.html