zoukankan      html  css  js  c++  java
  • [牛客挑战赛 30D] 小A的昆特牌 解题报告 (组合数学)

    interlinkage:

    https://ac.nowcoder.com/acm/contest/375/D

    description:

    solution:

    • 我们枚举步兵的数量$x$,还剩下$S-x$张牌。$x$张步兵要分成$n$份,$S-x$剩下的要分成$m+1$份,其中第$m+1$份的含义是不锻造,注意可以为空
    • $ans=sum_{x=l}^{r}dbinom{x+n-1}{n-1}dbinom{S-x+m}{m}$
    • 但是直接这样算的话要么爆时间,要么爆空间
    • 发现答案的式子其实相当于从$(0,0)$走到$(S,n+m)$必须经过线段$(l,n)->(r,n)$的方案数
    • 可能有人会疑惑为什么是从$(0,0)$走到$(S,n+m)$,感觉像是走到$(S,n+m+1)$啊。但是仔细观察会发现,因为我们枚举的是与线段$(l,n)->(r,n)$的交点,也就是说当走到$y=n$的时候交点就已经固定了,就不能再向右走了。因此从$(0,0)$到$(x,n)$相当于把$x$个横步插入到$n$个部分中。从$(x,n)$到$(S,n+m)$相当于把$S-x$的横步插入到$m+1$个部分中,因为这个时候走到$y=n+m$的时候还可以向右走
    • 该方案数=第$l$步向右走时走到纵坐标$(0,n-1)$的方案数-第$r+1$步向右走时走到纵坐标$(0,n-1)$的方案数
    • 走到第$p$步向右走时走到纵坐标$(0,n-1)$的方案数为$sum_{i=0}^{n-1}dbinom{p+i-1}{p-1}dbinom{S-p+n+m-i}{S-p}$
    • 这样就比较好算了
    #include<bits/stdc++.h>
    using namespace std;
    
    const int N=2e7+5,P=998244353;
    inline int add(int x,int y){return x+y>=P?x+y-P:x+y;}
    inline int dec(int x,int y){return x-y<0?x-y+P:x-y;}
    inline int mul(int x,int y){return 1ll*x*y-1ll*x*y/P*P;}
    int inv[N],f[N],g[N];
    int n,m,s,l,r;
    int calc(int p)
    {
        if(p>s)return 0;
        int res=0;
        f[0]=g[0]=1;
        for (int i=1;i<=n+m;i++)
        {
            g[i]=1ll*g[i-1]*(p+i-1)%P*inv[i]%P,
            f[i]=1ll*f[i-1]*(s-p+i)%P*inv[i]%P;
        }
        for (int i=0;i<n;i++) res=add(res,mul(f[n+m-i],g[i]));
        return res;
    }
    int main()
    {
        scanf("%d%d%d%d%d",&n,&m,&s,&l,&r);
        inv[0]=inv[1]=1;
        for (int i=2;i<N;i++) inv[i]=1ll*(P-P/i)*inv[P%i]%P;
        printf("%d
    ",dec(calc(l),calc(r+1)));
        return 0;
    }
  • 相关阅读:
    111
    实验 12 综合练习二
    实验 11结构体
    作业 5 指针应用1
    实验 10 指针2
    实验9 指针1
    实验8 数组2
    实验7
    321
    实验9-2
  • 原文地址:https://www.cnblogs.com/xxzh/p/10693902.html
Copyright © 2011-2022 走看看