满足条件的01序列

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

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

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

数据范围
1 ≤ n ≤ 1 e 5 1≤n≤1e5 1n1e5


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

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

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

( 0 , 0 ) (0,0) (0,0) ( 6 , 6 ) (6,6) (6,6)的方法总数为 C 12 6 C_{12}^6 C126 , 从 ( 0 , 0 ) (0,0) (0,0) ( 5 , 7 ) (5,7) (5,7)的方法总数为 C 12 5 C_{12}^5 C125
n = 6 n=6 n=6时,所以最后的答案为 C 12 6 − C 12 5 C_{12}^6 - C_{12}^5 C126C125
……
类似的,当 n = n n=n n=n时,答案为 C 2 n n − C 2 n n − 1 C_{2n}^n - C_{2n}^{n-1} C2nnC2nn1
化简得出:
C 2 n n − C 2 n n − 1 = C 2 n n n + 1 C_{2n}^n - C_{2n}^{n-1} = \frac{C_{2n}^n}{n+1} C2nnC2nn1=n+1C2nn
在这里插入图片描述

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;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值