#莫队,排列组合,容斥原理,卡特兰数#洛谷 4260 [Code+#3] 博弈论与概率统计

题目传送门


分析

由于赢的场数是固定的,所以概率并没有用,要想得分足够高,那就应该先输后赢

设输的场次为 -1,赢的场次为 1,得分前缀和为 \(s\),那么得分就是 \(n-m-\min\{s\}\)

如果将输视为向上移,将赢视为向右移,那么恰好得到某个最小前缀和为 \(-k\) 的方案数

相当于恰好碰到 \(y=x+k\) 又不能碰到 \(y=x+k+1\) 的方案数,那么将 \((0,0)\) 对称到 \((-k,k)\)

容斥一下就是 \(C(n+m,n+k)-C(n+m,n+k+1)\) 乘上得分 \(n-m+k\)

由于得分不能为负值,所以分 \(n>m\)\(n\leq m\) 两类讨论

对于第一类情况,相当于求解 \(\sum_{k=0}^m(n-m+k)[C(n+m,n+k)-C(n+m,n+k+1)]\)

将两项分开计算得到答案为 \((n-m)C(n+m,n)+\sum_{k=0}^{m-1}C(n+m,k)\)

对于第二类情况,相当于求解 \(\sum_{k=m-n}^{m}(n-m+k)[C(n+m,n+k)-C(n+m,n+k+1)]\)

将两项分开计算得到答案为 \(\sum_{k=0}^{n-1}C(n+m,k)\)

最后答案都除以 \(C(n+m,m)\) 就可以得到期望得分

\(f(n,m)=\sum_{i=0}^mC(n,i)\),则 \(f(n,m)=f(n,m-1)+C(n,m),f(n,m)=2f(n-1,m)-C(n-1,m)\)

所以对于后面的和式可以根据 \(n,m\) 的增减计算,用莫队解决


代码

#include <cstdio>
#include <cctype>
#include <algorithm>
using namespace std;
const int mod=1000000007,N=250011;
struct rec{int n,m,rk;}q[N];
int pos[N],fac[N],inv[N],ans[N],Q;
int iut(){
    int ans=0,f=1; char c=getchar();
    while (!isdigit(c)) f=(c=='-')?-f:f,c=getchar();
    while (isdigit(c)) ans=ans*10+c-48,c=getchar();
    return ans*f;
}
void print(int ans){
    if (ans>9) print(ans/10);
    putchar(ans%10+48);
}
bool cmp(rec x,rec y){
    if (pos[x.n]!=pos[y.n]) return pos[x.n]<pos[y.n];
    return (pos[x.n]&1)?(x.m<y.m):(x.m>y.m);
}
void Mo(int &x,int y){x=x+y>=mod?x+y-mod:x+y;}
int C(int n,int m){
    if (n<m) return 0;
    return 1ll*fac[n]*inv[m]%mod*inv[n-m]%mod;
}
int main(){
    fac[0]=fac[1]=inv[0]=inv[1]=1;
    for (int i=2;i<N;++i) inv[i]=1ll*(mod-mod/i)*inv[mod%i]%mod,pos[i]=i/500;
    for (int i=2;i<N;++i) fac[i]=1ll*fac[i-1]*i%mod,inv[i]=1ll*inv[i-1]*inv[i]%mod;
    Q=iut(),iut();
    for (int i=1;i<=Q;++i){
        int n=iut(),m=iut();
        if (n>m) ans[i]=n-m,q[i]=(rec){n+m,m-1,i};
            else q[i]=(rec){n+m,n-1,i};
    }
    sort(q+1,q+1+Q,cmp);
    int n=0,m=0,now=1;
    for (int i=1;i<=Q;++i){
    	int t=1ll*inv[q[i].n]*fac[q[i].m+1]%mod*fac[q[i].n-q[i].m-1]%mod;
        while (n>q[i].n) Mo(now,C(--n,m)),now=500000004ll*now%mod;
        while (n<q[i].n) Mo(now,now),Mo(now,mod-C(n++,m));
        while (m<q[i].m) Mo(now,C(n,++m));
        while (m>q[i].m) Mo(now,mod-C(n,m--));
        Mo(ans[q[i].rk],1ll*now*t%mod);
    }
    for (int i=1;i<=Q;++i) print(ans[i]),putchar(10);
    return 0;
}
posted @ 2024-04-07 03:44  lemondinosaur  阅读(14)  评论(0编辑  收藏  举报