题目描述
lxhgww最近接到了一个生成字符串的任务,任务需要他把n个1和m个0组成字符串,但是任务还要求在组成的字符串中,在任意的前k个字符中,1的个数不能少于0的个数。现在lxhgww想要知道满足要求的字符串共有多少个,聪明的程序员们,你们能帮助他吗?
解析:
这道题非常有意思,凝聚了组合数学和数形结合的思想,在处理的过程中还要用到乘法逆元。我们可以把它转化到一张网格图上,对于每次选0或选1,我们可以让他对应每次向右下或右上走,那么走到(n,n-m)的方案有多少种。考虑到不能让某一时刻的0的个数比1多,我们只需减去经过y=-1的方案数即可对于不合法的方案,把第一次碰到y=-1之前的折线翻折一下可以看成从(-2,0)走到(n+m,n-m)的方案数,即 C(n+m,m)-C(n+m,m-1);
#include <iostream>
#include <cstdio>
#define ll long long
using namespace std;
const ll N=20100403;
ll n,m,tot,unf,ans;
inline ll read()
{
ll f=1,x=0;char c=getchar();
while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}
while (c>='0'&&c<='9') {x=x*10+c-'0';c=getchar();}
return f*x;
}
inline ll pow(ll x,ll y)
{
if (y==0) return 1;
ll k=1;
while (y)
{
if (y&1) k=k*x%N;
y/=2;
x=x*x%N;
}
return k;
}
int main()
{
n=read();m=read();
tot=unf=1;
for (ll i=m+1;i<=n+m;i++)
tot=tot*i%N*pow(i-m,N-2)%N;
for (ll i=m;i<=n+m;i++)
unf=unf*i%N*pow(i-m+1,N-2)%N;
ans=((tot-unf)%N+N)%N;
printf("%lld",ans);
return 0;
}
代码: