2018.10.04【BZOJ1856】【SCOI2010】字符串(组合数学)

传送门


解析:

这不就是一个组合数学的乱搞题吗?

思路:

相信大家应该都做过平面坐标系上,只能向右或向上移动,问到达终点的方案数这种问题。

那么我们试着将这道题转化成上面这个问题。

令我们拥有一个空的队列,我们试着向队列中加入0或1,满足任意时刻1的个数不少于0的个数。若当前队列里面有 x x x个1和 y y y个0,则该队列当前状态对应的平面坐标为 ( x , y ) (x,y) (x,y)

那么上面的问题等价于,从 ( 0 , 0 ) (0,0) (0,0)出发,不经过任何 x &lt; y x&lt;y x<y的点 ( x , y ) (x,y) (x,y)到达 ( n , m ) (n,m) (n,m)的方案数。

这是一个小学奥数题。。。

我们将坐标系旋转,可以将它看成一个帕斯卡三角形,如果不考虑不能到达的情况,那么从 ( 0 , 0 ) (0,0) (0,0)走到 ( x , y ) (x,y) (x,y)的方案数就是 ( x + y x ) \begin{pmatrix}x+y\\ x \end{pmatrix} (x+yx)。再减去不合法的方案数 ( x + y y − 1 ) \begin{pmatrix}x+y\\y-1\end{pmatrix} (x+yy1)就行了。注意特判终点在不合法范围的情况。


代码:

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define re register
#define gc getchar
#define pc putchar
#define cs const
 
inline
ll getint(){
    re ll num;
    re char c;
    while(!isdigit(c=gc()));num=c^48;
    while(isdigit(c=gc()))num=(num<<1)+(num<<3)+(c^48);
    return num;
}
 
inline void outint(ll a){
    static char ch[23];
    if(a==0)pc('0');
    while(a)ch[++ch[0]]=a-a/10*10,a/=10;
    while(ch[0])pc(ch[ch[0]--]^48);
}
 
cs ll mod=20100403;
 
ll fac[2000005],inv[2000005],ifac[2000005];
inline
ll C(int n,int m){
    return fac[n]*ifac[m]%mod*ifac[n-m]%mod;
}
 
int n,m;
signed main(){
    fac[0]=fac[1]=inv[0]=inv[1]=ifac[0]=ifac[1]=1;
    n=getint(),m=getint();
    for(int re i=2;i<=m+n;++i)
    fac[i]=fac[i-1]*1ll*i%mod,
    inv[i]=(mod-mod/i)*inv[mod%i]%mod,
    ifac[i]=ifac[i-1]*inv[i]%mod;
     
     
    if(n<m) outint(0);
    else outint( (C(n+m,n) - C(n+m,m-1)+mod)%mod );
    return 0;
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值