括号串

题目描述

小 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\% 的数据,1\leq n\leq 20\)

\(对于 40\% 的数据,1\leq n\leq 2\times10^3\)

\(对于 100\% 的数据,1\leq n\leq 2\times10^6,1\leq Q\leq 2\times10^5,10^7\leq M\leq 2\times10^9\)

题目分析

显然n个括号匹配的括号对数\(\lfloor \frac{n}{2} \rfloor\)

分情况讨论,令\(m=\lfloor \frac{n}{2} \rfloor\)

当n是偶数时,问题为m对括号组成配对括号串方案数,显然就是catalan数第m项

当n是奇数时,需要推导

因为左右括号情况对称,故假设插入右括号

'(' 为 +1,')' 为 -1,对于每一个括号串可以得到一个前缀和数组 \(a\),只有当 \(a_i=0\)时,这个位置才能插入右括号保证不重复也不遗漏。

\(a_i \neq 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\n",catalan[n/2]);
        }else{
            printf("%lld\n",2*catalan[n/2+1]%Mod);
        }
    }
}
posted @ 2021-08-11 21:43  Z-Y-Y-S  阅读(49)  评论(0编辑  收藏  举报