洛谷4260:博弈论与概率统计(组合数学+莫队/分块)

题面
题意:小L在玩游戏,赢了n场,输了m场
赢一场得1分,输一场扣1分
若当前为0分,则不会扣
问期望得分

前置技能
有一个n个1和m个-1的序列,求前缀和最小值≥0的方案数
考虑不合法的
找到第一个和为-1的前缀
将其1与-1翻转
得到一个有 n+1 n + 1 个1和 m1 m − 1 个-1的序列
恰好与不合法的方案一一对应

类比得前缀和最小值恰好为 i − i 的方案数为 Cn+in+mCn+i1n+m C n + m n + i − C n + m n + i − 1

考虑n≥m
前缀和最小值为i贡献为n-m+i

经过一轮画柿子,错位相减
答案为 (nm)Cnn+m+mi=0Cin+m ( n − m ) ∗ C n + m n + ∑ i = 0 m C n + m i

f(n+m,m)=mi=0Cin+m f ( n + m , m ) = ∑ i = 0 m C n + m i

f(i,j) f ( i , j ) O(1) O ( 1 ) 推出 f(i+1,j) f ( i + 1 , j ) f(i,j1) f ( i , j − 1 )
故可用莫队或分块优化

#include <iostream>
#include <fstream>
#include <algorithm>
#include <cmath>
#include <ctime>
#include <cstdio>
#include <cstdlib>
#include <cstring>

using namespace std;
#define mmst(a, b) memset(a, b, sizeof(a))
#define mmcp(a, b) memcpy(a, b, sizeof(b))

typedef long long LL;

const LL p=1e9+7;
const int N=600300,nn=550;

int T,Violet;
LL jc[N],Ijc[N],I[N],ans[N],now=1;
int n[N],m[N];
int L=1,R;

struct yy
{
    int l,r,num;
}f[N];

bool cmp(yy x,yy y)
{
    if((x.l/nn)==(y.l/nn))
    return x.r<y.r;
    return (x.l/nn)<(y.l/nn);
}

LL C(int x,int y)
{
    return jc[x]*Ijc[y]%p*Ijc[x-y]%p;
}

LL IC(int x,int y)
{
    return Ijc[x]*jc[y]%p*jc[x-y]%p;
}

int main()
{
    I[1]=jc[0]=Ijc[0]=1;
    for(int i=2;i<N;i++)
    I[i]=I[p%i]*(p-p/i)%p;

    for(int i=1;i<N;i++)
    jc[i]=jc[i-1]*i%p,Ijc[i]=Ijc[i-1]*I[i]%p;

    cin>>T>>Violet;
    for(int i=1;i<=T;i++)
    {
        f[i].num=i;
        scanf("%d%d",&n[i],&m[i]);
        f[i].l=n[i]+m[i];
        if(n[i]<m[i])
        f[i].r=n[i]-1;
        else
        f[i].r=m[i]-1;
    }

    sort(f+1,f+T+1,cmp);

    for(int i=1;i<=T;i++)
    {
        int l=f[i].l,r=f[i].r;
        while(L<l)
        now=(now+now-C(L,R)+p)%p,L++;
        while(L>l)
        now=(now+C(L-1,R))%p*I[2]%p,L--;
        while(R<r)
        now=(now+C(L,R+1))%p,R++;
        while(R>r)
        now=(now-C(L,R)+p)%p,R--;
        ans[f[i].num]=now;
    }

    for(int i=1;i<=T;i++)
    if(n[i]<m[i])
    printf("%lld\n",ans[i]*IC(n[i]+m[i],n[i])%p);
    else
    printf("%lld\n",(n[i]-m[i]+ans[i]*IC(n[i]+m[i],n[i])%p)%p);

    return 0;
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值