题意:
给定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 }