C.挖坑 卡特兰数列(mod998244353

题目来源:

http://acm.hrbust.edu.cn/contests/index.php?act=showproblem&cid=1366&p=C

Description
    Quasrain 和 FZ 是好朋友。Quasrain 善于挖坑而 FZ 善于填坑。
    这个游戏一共会持续 2N 天。在每一天都会有人挖坑或者填坑,并在本子上记录下“A”表示这天挖了坑,“B”表示填了坑。填坑必须填一个现存的还没有被填过的坑。
    作为素质优秀的熊孩子,他们保证在最后一天结束的时候一定会恰好填平所有坑。
    问本子上可能有多少种不同的 AB 序列
Input
    第一行一个数 T 表示数据组数(T<=100000)
    之后 T 行每行一个数 N,意义如题面所示(1<=N<=1000)

 

Output
    对于每组数据输出方案数,对 998244353 取模
Sample Input
    3
    1
    2
    3
Sample Output
    1
    2
    5
Hint
    对于第三组样例:
    可能的 AB 序列分别为:{AAABBB},{AABABB},{AABBAB},{ABAABB},{ABABAB}

题目意思就是求在后面的填坑数要大于前面的挖坑次序可能情况,我们可以把填坑看成入栈操作,挖坑看成出栈操作,即填坑的累计个数不小于挖坑的排列有多少种,标准的卡特兰数列;

什么是卡特兰数列:

特兰数是一个常用在计数情况中使用的一种特殊的数列,其分析如下:

分析:假设我们要求的出栈数为n,要得到的出栈序列为f(n),我们知道,因为入栈的顺序是确定的,假设入栈顺序记为1、2、3、4、5...n,那么假设最后出栈的那个数为第k个数,那么我们要求f(k)时,k-1个数已经先完成进栈出栈,此时有f(k-1)种方式,然后k之后的n-k个数也完成进栈和出栈,也就是f(n-k)种方式,最后第k个数出栈,此时的f(k)=f(k-1)*f(n-k),而每个数都可能是最后出栈,可以得到通式:

                                    f(n)=\sum_{k=1}^{n}f(k-1)(n-k)

                       其递推公式的通解(f(0)=1):

                                                        1:f(n)=C(2n,n)/n+1

                                                        2:f(n)=C(2n,n)-C(2n,n+1)))

                                                        3:f(n)=f(n-1)(4n-2)/(i+1);

坑点:由于我只知道第一个和第三个式子,存在除法取余,比赛的时候不会写逆元

另外记录一些取模公式:

  1. a + b) % mod = (a % mod + b % mod) % mod  (1)

  2. (a - b) % mod= (a % mod - b % mod) % mod    (2)

  3. (a * b) % mod = (a % mod * b % mod) % mod(3)

  4. a ^ b %  mod = ((a % mod)^b) % mod             (4)

  • 结合律:

    ((a+b) % nod + c) % mod = (a + (b+c) % mod) % mod        (5)

        ((a*b) % mod * c)% mod = (a * (b*c) % mod) % mod            (6)

  • 交换律:

    (a + b) % mod = (b+a) % mod (7)

        (a * b) % mod = (b * a) % mod (8)

  • 分配律:

        ((a +b)% mod * c) % mod = ((a * c) % mod + (b * c) % mod) % mod (9)

 

费马定理小定理:a^b%mod=a^(b%(mod-1))%mod

                             a/b%mod=a*(1/b)%mod=a*b^(mod-2)%mod

(这里b^(mod-2)就是b的逆元)

参考代码:

#include<iostream>
using namespace std;
const int N=1e3;
const int mod=998244353;
typedef long long ll;
ll qpow(ll m,ll q)
{
    ll ans=1;
    while(q)
    {
        if(q&1)
            ans=ans*m%mod;
        m=m*m%mod;
        q>>=1;
    }
    return ans;
}
ll inv[N+5];
ll getinv(ll n)
{
    ll num3=qpow(n,mod-2);
    return num3;
}
int main()
{
    inv[1]=1,inv[2]=2;
    for(ll i=3; i<=1005; i++)
    {
        ll num1=inv[i-1]*(4*i-2)%mod;
        ll num2=getinv(i+1);
        inv[i]=num1*num2%mod;
    }
    ll t,n;
    cin>>t;
    while(t--)
    {
        cin>>n;
        cout<<inv[n]<<endl;;
    }
    return 0;
}

DP代码:

#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
#define ll long long int
#define N 1005
#define mod 998244353
using namespace std;
ll dp[N][N];
int main()
{
//    	freopen("E:c++.txt","w",stdout);
    memset(dp,0,sizeof(dp));
    for(int i=0; i<=1000; i++)
        dp[i][0]=1;//当挖坑的数量为零时,数量为1
    for(int i=1; i<=1000; i++)
        for(int j=1; j<=i; j++)
            dp[i][j]=(dp[i][j-1]+dp[i-1][j])%mod;//dp[i][j]的方案数为填掉上一个的数量dp[i-1][j]和挖一个填一个的数量dp[i][j-1];
    int t,n;
    cin>>t;
    while(t--)
    {
        cin>>n;
        cout<<dp[n][n]<<endl;
    }
    return 0;
}

卡特兰数详细证明过程请参考:https://blog.csdn.net/nuoyanli/article/details/88928767

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

nuoyanli

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值