zoukankan      html  css  js  c++  java
  • 【LOJ6513】「雅礼集训 2018 Day10」足球大战(数学题)

    点此看题面

    大致题意: 已知主队每秒进球概率为(p),客队每秒进球概率为(q),求主队进球数大于客队的概率。

    推式子

    考虑枚举主队进球数(i),则客队进球数必然小于(i),因此可再枚举一个(j)表示客队进球数。

    显然,主队进球数为(i)的概率应为(p^i(1-p)^{n-i}),同理客队进球数为(j)的概率应为(q^j(1-q)^{n-j})

    而哪(i)场或哪(j)场进球是任意的,所以两式应各乘上一个组合数(C_n^i)(C_n^j)

    所以就可以得到这样一个式子:

    [sum_{i=1}^np^i(1-p)^{n-i}C_n^isum_{j=0}^{i-1}q^j(1-q)^{n-j}C_n^j ]

    (O(n))求值

    注意到(nle10^7),所以我们需要一边枚举(i),一边同时统计这个式子的值,这其实是可以实现的。

    我们用(p_1)存储(p^i)(p_2)存储((1-p)^{n-i})(q_1)存储(q^j)(q_2)存储((1-q)^{n-j})(sq)存储(sum_{j=0}^{i-1}q^j(1-q)^{n-j}C_n^j)(ans)存储答案。

    初始化(p_1=1,p_2=(1-p)^n,q_1=frac1q,q_2=(1-q)^{n+1},sq=ans=0)

    然后定义两个常量(tp)(tq)分别存储(frac1{1-p})(frac1{1-q})

    每次操作时,将(p_1)乘上(p)(p_2)乘上(tp)(q_1)乘上(q)(q_2)乘上(tq)(sq)加上(q_1q_2C_n^{i-1})(ans)加上(p_1*p_2*C_n^i*sq)即可。

    关于内存

    这道题内存其实是卡得很紧的,而(nle10^7),差不多只能开一个数组。

    但光组合数就需要阶乘和阶乘逆元两个数组啊!

    不过,注意到此题中的组合数都是(C(n,x))的格式,因此所需用到的阶乘只有(n!),这可以直接预处理。然后就只需要一个阶乘逆元的数组即可。

    某些特判

    上面的式子,在某些特殊情况下其实是过不去的。

    1. (p=0)时,需直接输出(0)
    2. (q=0)时,需输出(1-(1-p)^n),即除非主队一球不进,否则必胜。
    3. (p=1)时,需输出(1-q^n),即除非客队全进,否则必胜。

    代码

    #include<bits/stdc++.h>
    #define Tp template<typename Ty>
    #define Ts template<typename Ty,typename... Ar>
    #define Reg register
    #define RI Reg int
    #define Con const
    #define CI Con int&
    #define I inline
    #define W while
    #define N 10000000
    #define X 1000000007
    #define Qinv(x) Qpow(x,X-2)
    #define C(x) (1LL*Fn*Inv[x]%X*Inv[n-(x)]%X)
    #define Inc(x,y) ((x+=(y))>=X&&(x-=X))
    using namespace std;
    int n,p,q,Fn,Inv[N+5];
    I int Qpow(RI x,RI y) {RI res=1;W(y) y&1&&(res=1LL*res*x%X),x=1LL*x*x%X,y>>=1;return res;}
    I int XSub(RI x,CI y) {return (x-=y)<0&&(x+=X),x;}
    int main()
    {
    	RI i,x,y,ans=0;scanf("%d%d%d",&n,&x,&y),p=1LL*x*Qinv(y)%X,scanf("%d%d",&x,&y),q=1LL*x*Qinv(y)%X;//读入数据
    	if(!p) return putchar('0'),0;if(!q) return printf("%d",XSub(1,Qpow(XSub(1,p),n))),0;//特判p=0或q=0的情况
    	if(!(p^1)) return printf("%d",XSub(1,Qpow(q,n))),0;//特判p=1的情况
    	for(Fn=i=1;i<=n;++i) Fn=1LL*Fn*i%X;for(Inv[n]=Qinv(Fn),i=n-1;~i;--i) Inv[i]=1LL*Inv[i+1]*(i+1)%X;//预处理n!和阶乘逆元
    	RI tp=Qinv(XSub(1,p)),tq=Qinv(XSub(1,q)),p1=1,p2=Qpow(XSub(1,p),n),q1=Qinv(q),q2=Qpow(XSub(1,q),n+1),sq=0;//初始化变量
    	for(i=1;i<=n;++i)//O(n)求值
    	{
    		p1=1LL*p1*p%X,p2=1LL*p2*tp%X,q1=1LL*q1*q%X,q2=1LL*q2*tq%X,Inc(sq,1LL*q1*q2%X*C(i-1)%X),//更新数据
    		Inc(ans,1LL*p1*p2%X*C(i)%X*sq%X);//更新答案
    	}return printf("%d",ans),0;//输出答案
    }
    
  • 相关阅读:
    python 对xls写入信息
    Python 字符串前面加u,r,b,f的含义
    inner join 与 left join 之间的区别
    时间戳转换成日期展示的方法 且 搜索范围
    Python与C/C++相互调用(python2 调c++那个试了ok)
    爆库记录(X-Forwarded-For注入漏洞实战 记录)
    笔记
    墨者学习安全测试的网站(看起来很不错的样子 有空看看)
    sqlmap开源 测试sql注入的工具 各种参考链接
    菜鸟浅谈——web安全测试(这篇不错有空看看)
  • 原文地址:https://www.cnblogs.com/chenxiaoran666/p/LOJ6513.html
Copyright © 2011-2022 走看看