首先,将这个字符串抽象成平面直角坐标系,从(0,0)出发,那么每一个1可以看成类似(0,0)->(1,1)这样子走一步,则0就是(0,0)->(1,-1)这样走一步,所以,满足要求的字符串也就是不能走到y=-1的直线上
先撇开这个东西,思考一下满足条件的方案数有多少,直接求不好求,那么可以用总方案数-不满足条件的方案数求得,总方案数其实是很容易求的,我们知道字符串的长度为n+m,一共有n个1,那么只要求在n+m个位置里放置n个1的方案数即可(0就不用管了,放完1剩下的位置放0就好了),也就是求组合数C(n+m,n)
接下来要求的就是不满足条件的方案数,回到这个平面直角坐标系,如果不满足条件,那么一定经过y=-1这一条直线,那么我们将y=-1这条直线上面的翻折下来,见下图:
在这个例子中,我只翻折了一部分(也就这一部分需要翻折,也就是从(0,0)开始直到第一次接触y=-1的这一段),那么所有0操作(向右下走)都变成了1(向右上走),1都变成了0,可以发现,在我圈起来的那一部分之前的部分,0和1的数量持平,所以翻折后他们数量还是一样,但是在我圈起来的地方,0翻成了1,这是只有第一次接触y=-1时才会出现的特殊情况,所以,1的数量其实加了1,0的数量减了1,那么同上,只需要求C(n+m,n+1)就好了
所以,答案就是(C(n+m,n)-C(n+m,n+1))%20100403
但是由于n,m较大,且除法不可以直接取模,所以我们需要运用逆元来求解
逆元:若 a b≡1(mod p) ,则b是a在模p意义下的逆元,也就是(a b)%p≡1
(下面的式子若无特殊标记,则都是在模p意义下的式子)
则 a/b=a * b的逆元
那么转换成乘法后,就可以直接取模了
那么逆元怎么求,请参见费马小定理,大致就是若a与p互质,且p是质数时,a^(p-1)≡1 ,并且,a^-1也是a的逆元
那么有
a^(p-1)=1=a^-1a
a^(p-1)=a^-1a
a^(p-2)=a^-1
所以,a的逆元就是a^(p-2),至于为什么不用a^-1,是因为它可能是个小数
所以组合数(这只是个例子)
n!
C(n,m)=————————= n! * (m! * (n-m)!)^20100403
m!(n-m)!
注意其中每一步运算都很大,所以每算一步都要模一次
接下来上代码:
#include <cstdio>
#include <cstring>
#define intt long long
#define mod 20100403
intt n,m;
intt C(intt x,intt y)
{
intt a=1;
for(intt i=2;i<=x;i++)//n!
a=(a*i)%mod;
intt b=1;
for(intt i=2;i<=y;i++)//m!
b=(b*i)%mod;
intt c=1;
for(intt i=2;i<=x-y;i++)//(n-m)!
c=(c*i)%mod;
b=(b*c)%mod;
intt d=1;//存(m!*(n-m)!)的逆元
intt p=mod-2;
while(p>0)//快速幂求逆元
{
if(p%2==1)d=(d*b)%mod;
b=(b*b)%mod;
p/=2;
}
return (a*d)%mod;
}
int main()
{
scanf("%lld %lld",&n,&m);
printf("%lld",(C(n+m,n)-C(n+m,n+1)+mod)%mod);
}