CodePlus3月月赛 博弈论与概率统计

求n+m局游戏恰好赢了n局的游戏的期望得分
记胜为+1,负为-1
期望得分可以用每种序列的得分*该种序列出现概率求和,最后再除以恰好出现n个1的概率
由此可以发现每种序列出现概率是相同的,就是说这个p并没有什么用
 prei=ij=1ai   p r e i = ∑ j = 1 i a i
一种序列的得分可以表示为 aimin{prei} ∑ a i − m i n { p r e i }
问题变成求最小前缀和的期望
这个期望又等于 1i=pi ∑ i = − ∞ − 1 p i pi p i 为最小前缀和<= i的概率
当n>=m时,这个pi=C(n+m,m+i)
用Catalan数的推导过程不难证明
n< m时候要特判一部分pi
问题变成了求一段组合数的前缀和
si,j=jk=0Cki s i , j = ∑ k = 0 j C i k
si+1,j=si,jCi,j s i + 1 , j = s i , j − C i , j
我们可以按照 n+m n + m 分段打表弄

code:

#include<set>
#include<map>
#include<deque>
#include<queue>
#include<stack>
#include<cmath>
#include<ctime>
#include<bitset>
#include<string>
#include<vector>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<climits>
#include<complex>
#include<iostream>
#include<algorithm>
#define ll long long
using namespace std;

inline void read(int &x)
{
    char c; while(!((c=getchar())>='0'&&c<='9'));
    x=c-'0';
    while((c=getchar())>='0'&&c<='9') (x*=10)+=c-'0';
}
const int maxk = 755;
const int maxS = 750;
const int maxn = 500005;
const int maxm = 250005;
const int mod = 1e9+7;

int pw(int x,int k)
{
    int re=1;
    for(;k;k>>=1,x=(ll)x*x%mod) if(k&1)
        re=(ll)re*x%mod;
    return re;
}
int inv(int x){return pw(x,mod-2);}

int s[maxn],invs[maxn];
void pre()
{
    s[0]=1; for(int i=1;i<maxn;i++) s[i]=(ll)s[i-1]*i%mod;
    invs[maxn-1]=inv(s[maxn-1]);
    for(int i=maxn-2;i>=0;i--) invs[i]=(ll)invs[i+1]*(i+1)%mod;
}
int C(int n,int m){return (ll)s[n]*invs[m]%mod*invs[n-m]%mod;}

int L[maxk],f[maxk][maxm],tp;

int cal(int n,int m)
{
    if(m<0) return 0;
    int now=1;
    while(L[now+1]<=n) now++;
    int c=f[now][m];
    for(int i=L[now];i<n;i++)
    {
        c=(c<<1)-(i>=m?C(i,m):0);
        if(c>=mod) c-=mod;
        if(c<0) c+=mod;
    }
    return c;
}
int solve(int n,int m)
{
    if(n>=m) return cal(n+m,m-1);
    else return ((ll)(m-n-1)*C(n+m,m)%mod+cal(n+m,n))%mod;
}
int n,m,P;

int main()
{
    //freopen("tmp.in","r",stdin);
    //freopen("tmp.out","w",stdout);

    pre();
    for(L[tp=1]=1;;L[++tp]=L[tp-1]+maxS)
    {
        if(L[tp]>maxn) break;
        int i=L[tp]; f[tp][0]=1;
        for(int j=1;j<maxm;j++)
        {
            int c=i<j?0:C(i,j);
            f[tp][j]=(f[tp][j-1]+c)%mod;
        }
    }

    int T;read(T),read(P);
    while(T--)
    {
        read(n),read(m);
        int ans=(ll)(n-m)*C(n+m,m)%mod;
        ans=(ans+solve(n,m))%mod;
        ans=(ll)ans*inv(C(n+m,m))%mod;
        ans=(ans+mod)%mod;
        printf("%d\n",ans);
    }

    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值