[数论] 洛谷 P1641 生成字符串
题目描述
lxhgww最近接到了一个生成字符串的任务,任务需要他把n个1和m个0组成字符串,但是任务还要求在组成的字符串中,在任意的前k个字符中,1的个数不能少于0的个数。现在lxhgww想要知道满足要求的字符串共有多少个,聪明的程序员们,你们能帮助他吗?
输入输出格式
输入格式:
输入数据是一行,包括2个数字n和m
输出格式:
输出数据是一行,包括1个数字,表示满足要求的字符串数目,这个数可能会很大,只需输出这个数除以20100403的余数
输入输出样例
说明
limitation
每点2秒
对于30%的数据,保证1<=m<=n<=1000
对于100%的数据,保证1<=m<=n<=1000000
题解
- 对于这题,我们可以考虑将全部的方案-不合法的方案=合法的方案
- 先来考虑一下全部的方案,字符串的长度为n+m,在里面放n个1,方案数就是C(n+m,n)
- 那么怎么求出不合法的情况的方案呢
- 我们把放0、1当做是在平面直角坐标系上,放1就当做是(+1,+1),放0就当做是(+1,-1)那么当直线到达(x,-1)时,就是不合法的
- 然后我们把y=-1当做是对称轴,将我们形成的直线对称下来,然后我们可以发现其实就是从(0,-2)开始到达(n+m,n-m)的方案数就是不合法滴
- 最后的话,答案就是C(n+m,n)-C(n+m,m-1)
代码
1 #include <iostream> 2 #include <cstdio> 3 #define ll long long 4 using namespace std; 5 const ll mo=20100403; 6 ll n,m,p[2000050],q[2000050]; 7 ll C(ll x,ll y) { return q[x]*p[y]%mo*p[x-y]%mo; } 8 int main() 9 { 10 scanf("%lld%lld",&n,&m),p[0]=p[1]=q[0]=q[1]=1;; 11 for (ll i=2;i<=n+m;i++) p[i]=(mo-mo/i)*p[mo%i]%mo,q[i]=q[i-1]*i%mo; 12 for (ll i=2;i<=n+m;i++) p[i]=p[i-1]*p[i]%mo; 13 printf("%lld",((C(n+m,m)-C(n+m,m-1))%mo+mo)%mo); 14 return 0; 15 }