あなたの蛙が帰っています!
蛙蛙完成了一趟旅行,回家啦!但它还是没有去它心中非常想去的几个地方。总共有 N 个它 想去的目的地。蛙蛙下定了决心,它要做一个愿望清单,一定要让自己去那些想去的地方。蛙蛙 是这样做的:它会不定时地想起一个或多个目的地,然后按顺序写在愿望清单上。但是每次蛙蛙 出去旅行时,都会先去最近写在愿望清单上的地方,并且蛙蛙不会重复去一个目的地,但它会去 访问所有的目的地。蛙蛙有个最想去的地方,这个地方是它第一个想到的,但由于种种原因,这 个地方不能是第一个被蛙蛙访问的。蛙蛙脑中回想目的地的顺序是固定的,所以它想请问你,它最终访问这些目的地的顺序有多少种?
对于两种访问序列
和
,它们是不同的当且仅当存在至少一个
,使得
。
为了让大家不被卡题意,这里给出一句话题意:已知一个没有深度限制的栈的入栈序列为 ,且 不能第一个出栈。求合法的出栈序列个数。答案对 取模。
输入描述:
第一行一个数 ,表示蛙蛙有 组询问。
接下去 行,每行一个正整数 , 表示目的地的个数(入栈元素个数)。
输出描述:
输出共 行,每行一个答案,格式形如 ,具体可见样例。
答案可能较大,请对 取模后输出。
示例1
输入
3 3 9 24
输出
Case #1: 3 Case #2: 3432 Case #3: 508887030
说明
对于样例中的第一个询问,设三个目的地为 , , ,其中 是第一个目的地,所以不能第一个访问。则有三种合法访问序列:
·
·
·
备注:
题意:略
分析: 首先看到给的提示说了,第一个入栈的数不能先出,卡特兰数可以解决元素入栈出栈问题,我们可以根据递推公式,把1e5
的卡特兰数打表,然后会发现题目上所求的为:k[n] - k[n - 1]
,因为通项公式为:
k[0] = k[1] = 1;
k[n] = k[n - 1] * (4 * n - 2) / (n + 1)
注意这里用到了取模,当然别忘了用逆元啦~
参考代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e5 + 10,MOD = 998244353;
///h(n)=h(n-1)*(4*n-2)/(n+1)
ll res[maxn];
#define mod(x) (x) % MOD
ll qpow(ll a, ll b) {
ll res = 1;
while (b) {
if (b & 1) res = (res * a) % MOD;
a = (a * a) % MOD;
b >>= 1;
}
return res;
}
void init() {
res[0] = 0;
res[1] = 1;
res[2] = 2;
for (int i = 2; i < maxn; i++) {
res[i] = (mod(mod(res[i - 1] * (4 * i - 2)) *1ll * qpow(i + 1, MOD - 2)) + MOD ) % MOD;
}
}
int main() {
int T;cin>>T;
init();
for (int i = 1; i <= T; i++) {
int n;cin>>n;
if (n == 1) cout<<0<<endl;
else cout<<"Case #"<<i<<": "<<(res[n] - res[n - 1] + MOD + MOD) % MOD<<endl;
}
return 0;
}