【SCOI2010 DAY2】 字符串 --折线原理+乘法逆元

Description

时限:2s 
  lxhgww最近接到了一个生成字符串的任务,任务需要他把n个1和m个0组成字符串,但是任务还要求在组成的字符串中,在任意的前k个字符中,1的个数不能少于0的个数。现在lxhgww想要知道满足要求的字符串共有多少个,聪明的程序员们,你们能帮助他吗?

Input

  输入数据是一行,包括2个数字n和m

Output

  输出数据是一行,包括1个数字,表示满足要求的字符串数目,这个数可能会很大,只需输出这个数除以20100403的余数

Sample Input

2 2

Sample Output

2

Hint

对于30%的数据,保证1<=m<=n<=1000 
对于100%的数据,保证1<=m<=n<=1000000


【分析】

这道题跟《奥赛经典-奥林匹克数学中的组合问题》31页的题很是相似。

。。。
我们用一个N+M维向量(a1,a2,a3...a(N+M))来表示这个字符串的组成。
我们从左往右依次填入数字0和1,当第k次填入时:

    若填入1,则取ak=1
    若填入0,则取ak=-1
我们令bk=a1+a2+...+ak=sigma(ak)
在平面直角坐标系中从左往右依次连接以下格点(1,b1),(2,b2),(3,b3)...(k,bk)...(N+M,b(N+M)),得到一条含N+M-1节的折线,因为1的个数不小于0的个数,故bk>=0(k=1,2...N+M),且b1=1,b(N+M)=N-M。
可见折线是一条连接(1,1)与(N+M,N-M),且与直线y=-1没有公共点的折线。
首先总的方案数为


    A=C(N+M-1,(1/2)*((N+M-1)+(N-M-1)))=C(N+M-1,N-1)  

上升+下降=(N+M)-1

上升-下降=(N-M)-1

(从总的长度中选择需要的上升长度)
然后我们将格点(1,1)以直线y=-1为对称轴对称的点记为p点,p点坐标显然为(1,-3)。
那么不满足与直线y=-1没有公共点的折线的数量,就等价于p点与(N+M,N-M)间折线的方案数
即为


    B=C(N+M-1,(1/2)*((N+M-1)+(N-M-(-3))))=C(N+M-1,(1/2)*((N+M-1)+(N-M+3)))=C(N+M-1,N+1)


最后答案就是A-B,由于N和M很小,所以直接暴力求解计算出分子分母模20100403的值,然后求一个乘法逆元即可。
另:
A-B=C(m+n-1,n-1)-C(m+n-1,n+1)
   =C(n+m,n)*(n/(n+m))-C(n+m,n)*(m*(m-1)/(n+m)/n+1)
   =C(n+m,n)*((n-m+1)/(n+1))


【代码】

/***********************
    ID:Ciocio
	LANG:C++
	DATE:2014-1-20
	TASK:string
************************/
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <iostream>
#include <algorithm>
#include <queue>

using namespace std;

#define MODER 20100403

typedef long long LL;
LL N,M;

void _init()
{
	cin>>N>>M;
}

void _gcd(LL a,LL b,LL &d,LL &x,LL &y)
{
	if(!b){d=a;x=1;y=0;}
	else{_gcd(b,a%b,d,y,x);y-=x*(a/b);}
}

LL _inv(LL a,LL n)
{
	LL d,x,y;
	_gcd(a,n,d,x,y);
	return d==1?(x+n)%n:-1;
}

void _solve()
{
	LL fz,fm;
	fz=N-M+1;
	fm=N+1;
	for(int i=2;i<=N+M;i++) fz=(fz*i)%MODER;
	for(int i=2;i<=N;i++) fm=(fm*i)%MODER;
	for(int i=2;i<=M;i++) fm=(fm*i)%MODER;
		
	LL fm_1=_inv(fm,MODER);
	LL ans=fz*fm_1%MODER;
	cout<<ans<<endl;
}

int main()
{
	_init();
	_solve();
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值