[CodePlus 2018 3 月賽] 博弈論與概率統計


link

題意簡述

小 $A$ 與小 $B$ 在玩游戲,已知小 $A$ 贏 $n$ 局,小 $B$ 贏 $m$ 局,沒有平局情況,且贏加一分,輸減一分,而若只有 $0$ 分仍輸不扣分。

已知小 $A$ 每次贏得概率為 $p$ ,問小 $A$ 得分期望。 $T$ 組數據。

$T,n,m\leq 2.5\times 10^5$

$solution:$

因為贏場輸場已經固定,所以 $p$ 其實是沒有用,則現在考慮計算小 $A$ 得分總和。

將贏輸場前綴和,記為 $\{s\}$,則得分為 $n-m-min\{s\}$ 。假設所有 $-1$ 均有意義,則分數為 $n-m$ 。

設 $min\{s\}=x$,則第一次出現 $-1,-2,…,x$ 均無意義因為當時得分前為 $0$ 而又被 $-1$,無意義,共出現 $|x|$ 次情況,即得分為 $n-m-min\{s\}$。

所以現在的問題轉化為給定 $n$ 個 $1$ 與 $m$ 個 $-1$ ,問最小前綴和為 $w$ 的方案數。

基本操作,將問題轉化為平面移動問題。

若要求最小前綴和為 $w$ 的方案數,可以表示為從 $(0,0)$ 走到 $(n,m)$ 的方案數,每次往上或左走一步求經過 $y=x+w$ 但不能經過 $y=x+w+1$ 直線的方案數。

考慮求從 $(1,1)$ 到 $(n,m)$ 經過 $y=x+w$ 的方案數,可以將第一次經過 $y=x+w$ 的交點之前部分對 $y=x+w$ 對稱,則 $(0,0)$ 對稱到 $(-w,w)$ ,可以發現每次從 $(-w,w)$ 到 $(n,m)$ 經交點對稱后對應一條合法路徑,則其方案數為 $\dbinom{n+m}{n+w}$ 。

通過簡單容斥原理得到若最小前綴和為 $w​$ 的方案數為 $\dbinom{n+m}{n+w}-\dbinom{n+m}{n+w+1}​$ 。

考慮贏 $n​$ 場輸 $m​$ 場的得分,得分區間為 $[max\{0,n-m\},n]​$ 。

分類討論 $n,m$ 大小。

若 $n\geq m$ ,則得分區間在 $[n-m,n]$ , $min\{s\}\in [-m,0]$。

$$Ans=\sum_{i=0}^{m} (n-m+i) (\dbinom{n+m}{n+i}-\dbinom{n+m}{n+i+1})\\=(n-m) \sum_{i=0}^m(\dbinom{n+m}{n+i}-\dbinom{n+m}{n+i+1}) +\sum_{i=0}^m i\times (\dbinom{n+m}{m-i}-\dbinom{n+m}{m-i-1})\\=(n-m)\dbinom{n+m}{n}+\sum_{i=0}^{m-1} \dbinom{n+m}{i}​$$

若 $n<m​$ ,則同理 $min\{s\}\in [{-m,n-m}]​$

$$Ans=\sum_{i=m-n}^m (n-m+i)\times\dbinom{n+m}{m-i}-\dbinom{n+m}{m-i-1}\\=(n-m)\dbinom{n+m}{n}+\sum_{i=m-n}^m i\times \dbinom{n+m}{m-i}-\sum_{i=m-n}^{m-1} i\times \dbinom{n+m}{m-i-1}\\=(n-m)\dbinom{n+m}{n}+(m-n)\dbinom{n+m}{n}+\sum_{i=m-n+1}^m i\times \dbinom{n+m}{m-i}-\sum_{i=m-n}^{m-1} i\times \dbinom{n+m}{m-i-1}\\=\sum_{i=m-n+1}^{m-1} i\times\dbinom{n+m}{m-i}-\sum_{i=m-n+1}^{m} (i-1)\times \dbinom{n+m}{m-i+1}\\=\sum_{i=m-n+1}^{m} \dbinom{n+m}{m-i}\\=\sum_{i=0}^{n-1}\dbinom{n+m}{i}​$$

可以發現現在的問題為如何快速求 $F(n,k)=\sum_{i=0}^k \dbinom{n}{i}$

可以發現 $F(n,k)=\sum_{i=0}^k \dbinom{n-1}{i-1}+\dbinom{n-1}{i}=2\times F(n-1,k)-\dbinom{n-1}{k}$ 。即 $F(n,k)$ 與 $F(n-1,k)$ 和 $F(n,k-1)$ 都有遞推關系。

直接將答案離線后莫隊計算即可。

時間復雜度 $O((n+m)\sqrt{n+m})$ 。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath> 
#define int long long
#define mod 1000000007
using namespace std;
inline int read(){
    int f=1,ans=0;char c=getchar();
    while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    while(c>='0'&&c<='9'){ans=ans*10+c-'0';c=getchar();}
    return ans*f;
}
const int MAXN=500001;
struct Query{
    int l,r,bl,id;
}query[MAXN],tmp[MAXN];
bool cmp(Query x1,Query x2){
    if(x1.bl!=x2.bl) return x1.l<x2.l;
    if(x1.bl&1) return x1.r<x2.r;
    return x1.r>x2.r;
}
int T,p,Ans[MAXN],inv[MAXN],ifac[MAXN],fac[MAXN];
inline void init(){
    fac[0]=1;for(int i=1;i<MAXN;++i) fac[i]=fac[i-1]*i,fac[i]%=mod;
    inv[1]=1;for(int i=2;i<MAXN;++i) inv[i]=(mod-mod/i)*inv[mod%i],inv[i]%=mod;
    ifac[0]=1;for(int i=1;i<MAXN;++i) ifac[i]=ifac[i-1]*inv[i],ifac[i]%=mod;
    return;
}
inline int C(int a,int b){if(a<b) return 0;return (((fac[a]*ifac[b])%mod)*ifac[a-b])%mod;}
inline int F(int a,int b){return (((fac[b]*fac[a-b])%mod)*ifac[a])%mod;}
inline int ksm(int a,int b){
    int ans=1;
    while(b){
        if(b&1) ans*=a,ans%=mod;
        a*=a,a%=mod;b>>=1;
    }return ans;
}
int blo,bl[MAXN],l,r,ans,inv2;
int Mod(int x){return ((x%mod)+mod)%mod;}
signed main(){
//    freopen("20.in","r",stdin);
    init();
    T=read(),p=read();blo=501;
    for(register int i=0;i<MAXN;++i) bl[i]=(i-1)/blo+1;
    for(register int i=1;i<=T;++i){
        int n=read(),m=read();
        if(n>=m) Ans[i]=(n-m)*C(n+m,n),query[i].l=n+m,query[i].r=m-1,query[i].bl=bl[query[i].l];
        else query[i].l=n+m,query[i].r=n-1,query[i].bl=bl[query[i].l];
        query[i].id=i;
        tmp[i].l=n,tmp[i].r=m;
    }sort(query+1,query+T+1,cmp);
    l=0,r=0,ans=1;inv2=ksm(2,mod-2);
    for(register int i=1;i<=T;++i){
        while(l<query[i].l) ans=Mod(2*ans-C(l,r)),l++;
        while(l>query[i].l) ans=Mod(Mod(ans+C(l-1,r))*inv2),l--;
        while(r<query[i].r) ans+=C(l,r+1),ans=Mod(ans),r++;
        while(r>query[i].r) ans-=C(l,r),ans=Mod(ans),r--;
        Ans[query[i].id]+=ans,Ans[query[i].id]%=mod;
    }
    for(register int i=1;i<=T;++i){Ans[i]*=F(tmp[i].l+tmp[i].r,tmp[i].l);Ans[i]%=mod;}
    for(register int i=1;i<=T;++i) printf("%lld\n",Ans[i]);
    return 0;
}
View Code

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM