满足条件的01序列

给定n个0和n个1,它们将按照某种顺序排成长度为2n的序列,求它们能排列成的所有序列中,能够满足任意前缀序列中0的个数都不少于1的个数的序列有多少个。
输出的答案对1e9+7取模。

输入格式
共一行,包含整数n。

输出格式
共一行,包含一个整数,表示答案。

数据范围
1≤n≤1e5


做法:
模型抽象:将01序列看成一个在坐标轴中的走法,0代表向右走,1代表向上走,一开始在(0,0)点,因为0与1都有n个,最后一定是从(0,0)走到了(n,n)

以6为例:
在这里插入图片描述
在来看条件:要求任意时刻0的个数不少于1的个数,因为0是向右走,1是向上走,也就是说 在坐标轴上任意一点处,都要求 x>=y
也就是所有的点都不能超过y=x这条直线:
在这里插入图片描述
我们可以求出从(0,0)走到(6,6)的所有走法a,在减去所有从(0,0)到(6,6)但不符合要求的走法b,所谓不符合要求就是该走法中存在点出现在y=x以上,也就是正好在y=x+1这条线上, 最后,a-b就是答案
在这里插入图片描述
现在来看一下如果有点在y=x+1这条直线上的话并且终点还是(6,6),这条直线有什么特点:

找到路线第一次与y=x+1相交的点,将该点上面的路线与y=x+1做一个对称路线,发现终点跑到了(5,7):
在这里插入图片描述
仔细想想可以发现:
所有从(0,0)到(5,7)的路线一定可以通过类似的方式转换成从(0,0)到(6,6)且经过y=x+1这条直线的路线

从(0,0)到(6,6)的方法总数为C(12,6) , 从(0,0)到(5,7)的方法总数为C(12,5)
当n=6时,所以最后的答案为 C(12,6) - C(12,5)
……
类似的,当n=n时,答案为C(2n,n) - C(2n,n-1)
化简得出:
C(2n,n) - C(2n,n-1) = C(2n,n) / (n+1)
在这里插入图片描述

const int mod = 1e9+7;

int power(int a,int b,int p)
{
    
    
	int res=1;
	while(b)	{
    
     if(b&1) res=(ll)res*a%p; a=(ll)a*a%p; b>>=1; }
	return res;
}

int C(int n,int m)
{
    
    
	int res=1;
	for(int i=1;i<=m;i++)	res=(ll)res*(n-m+i)%mod*power(i,mod-2,mod)%mod;
	return res;
}

int main()
{
    
    
	int n;
	cin>>n;
	
	int ans=(ll)C(2*n,n)*power(n+1,mod-2,mod)%mod; //除n+1 转换为 乘n+1的逆元 
	cout<<ans<<endl;
	
	return 0;
}

猜你喜欢

转载自blog.csdn.net/m0_50815157/article/details/113823846
今日推荐