zoukankan      html  css  js  c++  java
  • 【牛客挑战赛30D】小A的昆特牌(组合问题抽象到二维平面)

    点此看题面

    大致题意:(S)张无编号的牌,可以将任意张牌锻造成(n)种步兵或(m)种弩兵中的一种,求最后步兵数量大于等于(l)小于等于(r)的方案数。

    暴力式子

    首先我们来考虑暴力式子。

    假设我们确定了要选(x)个步兵数量,然后要求出此时的方案数。

    则我们就要使用隔板法

    仔细思考,其实我们就相当于要求出(x)个步兵分成(n)(S-x)个步兵分成(m+1)的方案数的乘积。(其中(m+1)组指的是(m)种弩兵以及不锻造这(m+1)种情况)

    而这两个要求的东西本质上是一样的。

    以把(x)个步兵分成(n)组为例,考虑到这是无编号的,因此我们完全可以假设每个步兵被分到的组号是递增的。

    那也就是说,我们要求把一个长度为(x)的序列分割成(n)部分(可以为空)的方案数。

    而分割成(n)部分,就相当于加入了(n-1)块隔板。

    如果把隔板也看做序列的一部分,则序列总长度就变成了(x+n-1),而分割就相当于要在这个序列中选出(n-1)个位置。

    因此方案数就是:

    [C_{x+n-1}^{n-1} ]

    同理,把(S-x)个步兵分成(m+1)组的方案数就是:

    [C_{s-x+m}^m ]

    于是它们的乘积就是:

    [C_{x+n-1}^{n-1}*C_{s-x+m}^m ]

    而最终答案就是:

    [sum_{x=l}^rC_{x+n-1}^{n-1}*C_{s-x+m}^m ]

    抽象问题到二维平面

    我们可以发现,这其实就相当于从((0,0))走到((S,n+m)),且必须经过点((l,n))下方,不能经过点((r+1,n))下方的方案数。

    这其实就相当于用经过点((l,n))下方的方案数减去经过点((r+1,n))下方的方案数。

    应该还是比较简单的。

    代码

    #include<bits/stdc++.h>
    #define Tp template<typename Ty>
    #define Ts template<typename Ty,typename... Ar>
    #define Reg register
    #define RI Reg int
    #define Con const
    #define CI Con int&
    #define I inline
    #define W while
    #define N 10000000
    #define X 998244353
    #define max(x,y) ((x)>(y)?(x):(y))
    #define Inc(x,y) ((x+=(y))>=X&&(x-=X))
    using namespace std;
    int n,m,s,l,r,Inv[(N<<1)+5],p1[N+5],p2[N+5];
    I int C(CI x,CI y)//求组合数
    {
    	if(x<y||x<0) return 0;RI i,res=1;//判断越界
    	for(i=1;i<=y;++i) res=1LL*res*(x-i+1)%X*Inv[i]%X;//统计答案
    	return res;//返回答案
    }
    I int Calc(CI x)//计算经过点(x,n)下方的方案数
    {
    	RI i,res=0;for(p1[0]=i=1;i^n;++i) p1[i]=1LL*p1[i-1]*(x-1+i)%X*Inv[i]%X;//计算p1
    	for(p2[n-1]=C(s-x+m+1,m+1),i=n-2;~i;--i) p2[i]=1LL*p2[i+1]*(s-x+n+m-i)%X*Inv[n+m-i]%X;//计算p2
    	for(i=0;i^n;++i) Inc(res,1LL*p1[i]*p2[i]%X);return res;//统计答案
    }
    int main()
    {
    	RI i,lim;scanf("%d%d%d%d%d",&n,&m,&s,&l,&r);
    	for(Inv[0]=Inv[1]=1,i=2,lim=max(n,m)<<1;i<=lim;++i) Inv[i]=1LL*(X-X/i)*Inv[X%i]%X;//线性求逆元
    	return printf("%d",(Calc(l)-Calc(r+1)+X)%X),0;//输出答案
    }
    
  • 相关阅读:
    ajax同步和异步
    vue组件
    type of的返回值有哪些
    git配置
    vue 获取时间戳对象转换为日期格式
    JavaScript运行机制
    单页面开发首屏加载慢,白屏如何解决
    单页面和多页面开发的优缺点
    【安全测试】sql注入
    【Python学习一】使用Python+selenium实现第一个自动化测试脚本
  • 原文地址:https://www.cnblogs.com/chenxiaoran666/p/Nowcoder30D.html
Copyright © 2011-2022 走看看