White and Black Balls 题解

我终于会 c a t a l a n catalan catalan 了hh。


link

题意:有 n n n 个白球, m m m 个蓝球,将这些球排成一排,记 w i w_i wi 表示 [ 1 , i ] [1, i] [1,i] 的白球的个数, b i b_i bi 表示 [ 1 , i ] [1, i] [1,i] 的蓝球的个数,要求 ∀ w i < b i + k \forall w_i < b_i + k wi<bi+k


我们考虑 m < n + k m < n + k m<n+k 的情况

W W W 操作当做 ( x , y ) → ( x + 1 , y ) (x, y) \rightarrow (x + 1, y) (x,y)(x+1,y),将 B B B 操作当做 ( x , y ) → ( x , y + 1 ) (x, y) \rightarrow (x, y + 1) (x,y)(x,y+1),那么终点是 ( n , m ) (n, m) (n,m)

举个例子,序列为 WBBWBBWW, k = 0 k = 0 k=0

在这里插入图片描述
怎么判断方案合不合法呢?如果发现路径和 y = x + k + 1 y = x + k + 1 y=x+k+1 相交,则不合法,否则合法。考虑容斥,方案总数是 C n + m n C_{n + m}^{n} Cn+mn,那么现在只考虑不合法的情况。

把这个路径在 y = x + k + 1 y = x + k + 1 y=x+k+1 以下的部分(除与 y = x + k + 1 y = x + k + 1 y=x+k+1 相交的最后一个点到 ( n , m ) (n, m) (n,m) 的路径)以 y = x + k + 1 y = x + k + 1 y=x+k+1 为对称轴翻折过去。如图所示。

在这里插入图片描述

这时候原点翻折到了 ( − k − 1 , k + 1 ) (-k - 1,k + 1) (k1,k+1),所有 ( − k − 1 , k + 1 ) → ( n , m ) (-k - 1, k + 1) \rightarrow (n, m) (k1,k+1)(n,m) 的路径都必定与 y = x + k + 1 y = x + k + 1 y=x+k+1 相交,所以把在 y = x + k + 1 y = x + k + 1 y=x+k+1 上方的部分翻折回去就是一种不合法的情况。

所以不合法的情况是: C ( n + k + 1 ) + ( m − k − 1 ) m − k − 1 = C n + m m − k − 1 C_{(n + k + 1) + (m - k - 1)}^{m - k - 1} = C_{n + m}^{m - k - 1} C(n+k+1)+(mk1)mk1=Cn+mmk1

那么最终答案就是: C n + m n − C n + m m − k − 1 C_{n + m}^{n} - C_{n + m}^{m - k - 1} Cn+mnCn+mmk1

#include <cstdio> 
#include <iostream>
#include <algorithm>
using namespace std;
#define LL long long

const int Maxn = 2 * 1e6;
const LL Mod = 1e9 + 7;

int n, m, k;
LL fac[Maxn + 5], inv_fac[Maxn + 5];

LL quick_pow (LL x, LL y) {
	LL res = 1;
	while (y) {
		if (y & 1) res = (res * x) % Mod;
		x = (x * x) % Mod; y >>= 1;
	}
	return res;
}
LL inv (LL x) {
	return quick_pow (x, Mod - 2);
}
LL C (LL x, LL y) {
	if (y == 0 || x == y) return 1;
	return fac[x] * inv_fac[y] % Mod * inv_fac[x - y] % Mod;
}

int main () {
	fac[1] = 1; for (int i = 2; i <= Maxn; i++) fac[i] = fac[i - 1] * i % Mod;
	inv_fac[Maxn] = inv (fac[Maxn]); for (int i = Maxn - 1; i >= 1; i--) inv_fac[i] = inv_fac[i + 1] * (i + 1) % Mod;
	
	cin >> m >> n >> k;
	if (n + k + 1 <= m) {
		printf ("0");
		return 0;
	}
	printf ("%lld", (C (n + m, n) - C (n + m, m - k - 1) + Mod) % Mod);
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值