题目描述
小 M 写下了一个长度为 n的括号串,使得其中能够成功匹配的括号对数尽可能多。
但第二天,小 M 却找不到她的括号串了,于是她去找小 K 帮忙,并仅仅告诉他括号串的长度。小 K 清楚的知道,这样的括号串有很多个,所以他问你,一共有多少个括号串满足要求呢?由于答案很大,他只需知道答案对 M取模后的结果。
输入格式
本题多测
第一行两个整数 Q,M,表示数据组数和模数,保证 M 是质数。
对于每组数据,一行一个整数 n,表示括号串长度。
输出格式
对于每组数据,一行一个整数,表示答案对 M 取模后的值。
输入输出样例
输入 #1
4 998244353
1
2
3
100
输出 #1
2
1
4
512803529
说明/提示
【样例解释】
当 n=1 时,满足要求的括号串为 (
和 )
。
当 n=2 时,满足要求的括号串为 ()
。
当 n=3 时,满足要求的括号串为 (()
, ()(
,)()
,())
。
【数据范围】
(对于 10\% 的数据,1leq nleq 20)
(对于 40\% 的数据,1leq nleq 2 imes10^3)
(对于 100\% 的数据,1leq nleq 2 imes10^6,1leq Qleq 2 imes10^5,10^7leq Mleq 2 imes10^9)
题目分析
显然n个括号匹配的括号对数(lfloor frac{n}{2} floor)
分情况讨论,令(m=lfloor frac{n}{2} floor)
当n是偶数时,问题为m对括号组成配对括号串方案数,显然就是catalan数第m项
当n是奇数时,需要推导
因为左右括号情况对称,故假设插入右括号
记 '('
为 +1,')'
为 -1,对于每一个括号串可以得到一个前缀和数组 (a),只有当 (a_i=0)时,这个位置才能插入右括号保证不重复也不遗漏。
当(a_i eq 0)插入右括号,尽管合法,但是会出现重复
所以需要求出(m)对括号的括号串,有多少情况满足(a_i=0)
枚举满足(a_i=0)之前的括号对数(k),即(i=2*k)
列出式子:(sum_{i=1}^{m}catalan(i)*catalan(m-i))
上式子等价于(catalan(m+1))最后考虑左括号(2*catalan(m+1))
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
typedef long long ll;
const int N=2000000;
int Mod,n;
ll inv[N+5],catalan[N+5];
int main(){
int Q;
cin>>Q>>Mod;
inv[1]=1;
for (int i=2;i<=N+2;i++)
inv[i]=((Mod-(Mod/i))*inv[Mod%i])%Mod;
catalan[1]=1;
for (int i=2;i<=N+1;i++){
catalan[i]=catalan[i-1]*(4*i-2)%Mod*inv[i+1]%Mod;
}
while (Q--){
scanf("%d",&n);
if (n%2==0){
printf("%lld
",catalan[n/2]);
}else{
printf("%lld
",2*catalan[n/2+1]%Mod);
}
}
}