Manasa and Combinatorics

题意:

给定n,求问由2n个字母B,n个字母A构成的字符串中

任意前缀B的个数大于A的个数且任意后缀B的个数大于A的个数的 字符串个数。

解法:

注意到答案不易于直接计算,所以我们考虑应用容斥原理。

注意到本题非常类似卡特兰数。

卡特兰数等价于从棋盘上$(1,1)$走到$(n,n)$且不穿过对角线的方案数。

1.先考虑求存在前缀B的个数<A的个数的方案数。

等价于从棋盘上$(1,1)$上走到$(2n,n)$ 且 穿过从$(1,1)$开始,以$(1,1)$为方向向量的直线$L$ 的 方案数。

当第一次穿过$L$时,必然是向右走了t步,向上走了t+1步,将从$(t,t+1)$开始的折线以L未为称轴翻折,

得到一个在棋盘上从$(1,1)$到$(n-1,2n+1)$的路径,

这样对于任意一个穿过$L$的从$(1,1)$到$(2n,n)$的行走方案 对应 一个 从$(1,1)$到$(n-1,2n+1)$的行走方案。

注意到任意一个从$(1,1)$到$(n-1,2n+1)$的路径也必然对应着一个从$(1,1)$到$(2n,n)$的穿过L的方案。

这样证明了两者一一对应,个数相同为 $C_{3n}^{n-1}$。

2.对于存在后缀B的个数<A的个数的方案数,同1得个数为 $C_{3n}^{n-1}$。

3.对于同时满足1,2的方案数,考虑对于原问题做1的等价之后,

问题转化为求 从$(1,1)$到$(n-1,2n+1)$ 且 经过 过终点的与L平行的直线 的路径数。

类比1中的方法进行再次翻折得到其个数为 $C_{3n}^{n-2}$

综上:答案为$C_{3n}^n - 2*C_{3n}^{n-1} + C_{3n}^{n-2}$

应用Lucas定理,计算总效率$O(P + logn)$

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 
 5 #define P 99991
 6 #define LL long long
 7 
 8 using namespace std;
 9 
10 LL fac[P];
11 
12 LL qpow(LL x,int n)
13 {
14     LL ans=1;
15     for(;n;n>>=1,x=x*x%P)
16         if(n&1) ans=ans*x%P;
17     return ans;
18 }
19 
20 LL C(int n,int m)
21 {
22     if(n<m) return 0;
23     return fac[n]*qpow(fac[m],P-2)%P*qpow(fac[n-m],P-2)%P;
24 }
25 
26 LL Lucas(LL n,LL m)
27 {
28     if(m<0) return 0; 
29     if(!m || !n) return 1LL;
30     return Lucas(n/P,m/P) * C(n%P,m%P)%P;
31 }
32 
33 int main()
34 {
35     fac[0]=1;
36     for(int i=1;i<P;i++) fac[i]=fac[i-1]*i%P;
37     LL n;
38     int T;
39     scanf("%d",&T);
40     while(T--)
41     {
42         cin>>n;
43         LL ans=Lucas(3*n,n)-2LL*Lucas(3*n,n-1)+Lucas(3*n,n-2);
44         cout << (ans%P+P) %P << endl;
45     }
46 }
View Code
原文地址:https://www.cnblogs.com/lawyer/p/6558961.html