题意是问有多少种长度为n的排列,满足前缀最大值是他本身的数量为A,后缀最大值是它本身的数量为B
如果你把每个前缀最大值和他后面的连续一段数放在一起,就相当于一个圆排列,每次断点都是这个最大值前面。
从最大值处把左右分开。
那么就相当于把长度
n
−
1
n - 1
n−1为排列分成
A
+
B
−
1
A + B - 1
A+B−1个圆排列的方案数。
还要乘上一个
(
A
+
B
−
1
A
−
1
)
\binom{A + B - 1}{A - 1}
(A−1A+B−1)表示从中选
A
−
1
A - 1
A−1个圆排列放在最大值左边
那么问题就变成了预处理第一类斯大林数(我知道是特x
根据他的递推式
S
n
m
=
S
n
−
1
m
−
1
+
(
n
−
1
)
S
n
−
1
m
S_n^m = S_{n - 1}^{m - 1} + (n - 1) S_{n - 1}^{m}
Snm=Sn−1m−1+(n−1)Sn−1m
可以得到
F
n
(
x
)
=
F
n
−
1
(
x
)
x
+
(
n
−
1
)
F
n
−
1
(
x
)
F_n(x)=F_{n - 1}(x)x + (n - 1)F_{n - 1}(x)
Fn(x)=Fn−1(x)x+(n−1)Fn−1(x)
那么发现它的生成函数是
F
n
(
x
)
=
∏
i
=
0
n
−
1
(
x
+
i
)
F_n(x) = \prod_{i = 0}^{n - 1} (x + i)
Fn(x)=i=0∏n−1(x+i)
显然可以分治NTT
但是我知道我的常数大如狗
于是这东西还可以倍增x
这样复杂度从
O
(
n
l
o
g
n
l
o
g
n
)
O(nlognlogn)
O(nlognlogn)变成了
O
(
n
l
o
g
n
)
O(nlogn)
O(nlogn)
我们可以考虑如何从前面一半推到后面一半
也就是从
∏
i
=
0
n
−
1
(
x
+
i
)
\prod_{i = 0}^{n - 1} (x + i)
∏i=0n−1(x+i)推到
∏
i
=
n
2
n
−
1
(
x
+
i
)
\prod_{i = n}^{2n - 1} (x + i)
∏i=n2n−1(x+i)
考虑二项式定理展开,设
∏
i
=
0
n
−
1
(
x
+
i
)
=
∑
i
=
0
n
f
i
x
i
\prod_{i = 0}^{n - 1} (x + i) = \sum_{i = 0} ^ n f_i x^i
∏i=0n−1(x+i)=∑i=0nfixi
就变成了
∏
i
=
n
2
n
−
1
(
x
+
i
)
=
∏
i
=
0
n
−
1
(
x
+
n
+
i
)
=
∑
i
=
0
n
f
i
(
x
+
n
)
i
=
∑
i
=
0
n
f
i
∑
j
=
0
i
(
i
j
)
x
j
n
i
−
j
\prod_{i = n}^{2n - 1} (x + i) = \prod_{i = 0}^{n - 1} (x + n + i) = \sum_{i = 0} ^ n f_i (x + n)^i \ = \sum_{i = 0} ^ n f_i \sum_{j = 0}^i \binom{i}{j} x ^ j n ^ {i - j}
i=n∏2n−1(x+i)=i=0∏n−1(x+n+i)=i=0∑nfi(x+n)i =i=0∑nfij=0∑i(ji)xjni−j
=
∑
j
=
0
i
1
j
!
n
j
x
j
∑
i
=
j
n
f
i
i
!
n
i
(
i
−
j
)
!
=
∑
j
=
0
i
1
j
!
n
j
x
j
∑
i
=
0
n
−
j
f
n
−
i
n
n
−
i
x
i
1
(
n
−
i
−
j
)
!
x
j
=\ \sum_{j = 0}^i \frac{1}{j! n ^ j} x ^ j \sum_{i = j} ^ n \frac{f_i i! n^i}{(i - j)!} = \ \sum_{j = 0}^i \frac{1}{j! n ^ j} x ^ j \sum_{i = 0} ^ {n - j} f_{n - i} n ^ {n - i} x ^ i \frac{1}{(n - i - j)!} x ^ j
= j=0∑ij!nj1xji=j∑n(i−j)!fii!ni= j=0∑ij!nj1xji=0∑n−jfn−inn−ixi(n−i−j)!1xj
显然后面是一个卷积
然后我们就可以卷积出后面的东西,然后再和前面的东西卷一卷,就做完了
主要是常数大,听说极限可以卡到分治NTT时间的
15
%
15\%
15%
/* ***********************************************
Author :BPM136
Created Time :2019/8/15 9:42:49
File Name :G.cpp
************************************************ */
#include <bits/stdc++.h>
#include <sys/timeb.h>
#define SZ(x) ((int)(x).size())
#define all(x) (x).begin(),(x).end()
#define USE_CIN_COUT ios::sync_with_stdio(0)
#define filein(x) freopen(#x".in","r",stdin)
#define fileout(x) freopen(#x".out","w",stdout)
#define file(x) freopen(#x".in","r",stdin),freopen(#x".out","w",stdout);
#define mkd(x) freopen(#x".in","w",stdout);
using namespace std;
int random(int l, int r) {
static std::random_device rd;
struct timeb timeSeed;
ftime(&timeSeed);
size_t seed = timeSeed.time * 1000 + timeSeed.millitm; // milli time
static std::mt19937 gen(seed);
std::uniform_int_distribution<> u(l, r);
return u(gen);
}
typedef long long ll;
typedef double db;
typedef long double ld;
typedef unsigned int ui;
typedef unsigned long long ull;
typedef pair<int, int> pii;
/eval多点求值,interpolation插值
//不可传入一个系数为负数的多项式,可能在减法的时候会爆mod
//常数稍微有点大
//G是TT的原根
//NTT前记得getRevRoot
int const TT = 998244353, G = 3;
inline int KSM (int a, int k) {
int ret = 1 % TT;
for (; k; k >>= 1, a = 1ll * a * a % TT)
if (k & 1)
ret = 1ll * ret * a % TT;
return ret;
}
inline int add (int x, int y) {
if (x + y >= TT)
return x + y - TT;
else
return x + y;
}
inline int sub (int x, int y) {
if (x - y >= 0)
return x - y;
else
return x - y + TT;
}
namespace Polynom
{
vector<int> rev, rt, e, one = {1};
vector<int> operator + (vector<int> f, vector<int> g) {
int n = (int)max(f.size(), g.size());
f.resize(n);
g.resize(n);
for (int i = 0; i < n; ++i)
f[i] = add(f[i], g[i]);
return f;
}
vector<int> operator - (vector<int> f, vector<int> g) {
int n = (int)max(f.size(), g.size());
f.resize(n);
g.resize(n);
for (int i = 0; i < n; ++i)
f[i] = sub(f[i], g[i]);
return f;
}
void getRevRoot (int n) {
int m = log(n) / log(2) + 1e-7;
rev.resize(n);
rt.resize(n);
for (int i = 1; i < n; ++i)
rev[i] = rev[i >> 1] >> 1 | (i & 1) << (m - 1);
for (int len = 1, uni; len < n; len <<= 1) {
uni = KSM(G, (TT ^ 1) / (len << 1));
rt[len] = 1;
for (int i = 1; i < len; ++i)
rt[i + len] = 1ll * rt[i + len - 1] * uni % TT;
}
}
void NTT (vector<int> &f, int n) {
f.resize(n);
for (int i = 0; i < n; ++i)
if (i < rev[i])
swap(f[i], f[rev[i]]);
for (int len = 1; len < n; len <<= 1)
for (int i = 0; i < n; i += len << 1)
for (int j = 0, x, y; j < len; j++) {
x = f[i + j];
y = 1ll * f[i + j + len] * rt[j + len] % TT;
f[i + j] = add(x, y);
f[i + j + len] = sub(x, y);
}
}
vector<int> operator * (vector<int> f, vector<int> g) {
int n = 1, m = (int)f.size() + (int)g.size() - 1, ivn;
while (n < m)
n <<= 1;
ivn = KSM(n, TT - 2);
getRevRoot(n);
NTT(f, n);
NTT(g, n);
for (int i = 0; i < n; ++i)
f[i] = 1ll * f[i] * g[i] % TT;
reverse(f.begin() + 1, f.end());
NTT(f, n);
f.resize(m);
for (int i = 0; i < m; ++i)
f[i] = 1ll * f[i] * ivn % TT;
return f;
}
vector<int> polyInv (vector<int> f, int m) {
if (m == 1)
return { KSM(f[0], TT - 2) };
f.resize(m);
vector<int> g = polyInv(f, m >> 1), h;
g.resize(m);
h.resize(m);
for (int i = (m >> 1) - 1; ~i; --i)
h[i] = (g[i] << 1) % TT;
int n = m << 1, ivn = KSM(n, TT - 2);
getRevRoot(n);
NTT(f, n);
NTT(g, n);
for (int i = 0; i < n; ++i)
f[i] = 1ll * f[i] * g[i] % TT * g[i] % TT;
reverse(f.begin() + 1, f.end());
NTT(f, n);
for (int i = 0; i < m; ++i)
h[i] = sub(h[i], 1ll * f[i] * ivn % TT);
return h;
}
vector<int> operator ~ (vector<int> f) {
int n = 1, m = (int)f.size();
while (n < m)
n <<= 1;
f = polyInv(f, n);
f.resize(m);
return f;
}
vector<int> polyDeri (vector<int> f) {
if (f.empty())
return f;
int n = (int)f.size();
for (int i = 1; i < n; ++i)
f[i - 1] = 1ll * f[i] * i % TT;
f.resize(n - 1);
return f;
}
vector<int> polyInte (vector<int> f) {
int n = (int)f.size();
f.resize(n + 1);
for (int i = n; ~i; --i)
f[i] = 1ll * f[i - 1] * KSM(i, TT - 2) % TT;
return f;
}
vector<int> polyLn (vector<int> f) {
int n = (int)f.size();
f = polyInte((~f) * polyDeri(f));
f.resize(n);
return f;
}
vector<int> polyExp (vector<int> f, int n) {
if (n == 1)
return one;
f.resize(n);
vector<int> g = polyExp(f, n >> 1);
g.resize(n);
return g * (one - polyLn(g) + f);
}
inline vector<int> polyExp (vector<int> f) {
int n = 1, m = (int)f.size();
while (n < m)
n <<= 1;
f = polyExp(f, n);
f.resize(m);
return f;
}
inline vector<int> operator ^ (vector<int> f, int x) {
int n = 0, m = (int)f.size();
while (n < m - 1 && !f[n])
n++;
f.erase(f.begin(), f.begin() + n);
e = {KSM(f.empty() ? 0 : f[0], x)};
f = polyLn(f);
f.resize(n = max(0ll, m - 1ll * n * x));
for (int i = 1; i < n; ++i)
f[i] = 1ll * f[i] * x % TT;
f = polyExp(f);
reverse(f.begin(), f.end());
for (int i = m - n; i; --i)
f.push_back(0);
reverse(f.begin(), f.end());
f.resize(m);
return f;
}
inline vector<int> operator / (vector<int> f, vector<int> g) {
int n = f.size(), m = g.size();
reverse(f.begin(), f.end());
reverse(g.begin(), g.end());
f.resize(n - m + 1);
g.resize(n - m + 1);
vector<int> ret = f * (~g);
ret.resize(n - m + 1);
reverse(ret.begin(), ret.end());
return ret;
}
inline vector<int> operator % (vector<int> f, vector<int> g) {
vector<int> ret = f / g;
ret = f - (g * ret);
ret.resize(g.size() - 1);
return ret;
}
} // namespace Polynom
using namespace Polynom;
int const N = 300005;
int const mod = 998244353;
int fac[N], fac_inv[N];
vector<int> solve(int n) {
if (n == 0)
return { 1 };
if (n == 1)
return { 0, 1 };
if (n & 1) {
auto g = solve(n - 1);
vector<int> t = { n - 1, 1 };
return g * t;
}
auto f = solve(n >> 1);
auto F = vector<int>(f.size(), 0);
auto G = vector<int>(f.size(), 0);
for (int i = 0; i < SZ(F); ++i) {
F[i] = 1ll * f[i] * fac[i] % mod * KSM(n / 2, i) % mod;
G[i] = fac_inv[i];
}
reverse(all(F));
auto H = F * G;
H.resize(F.size());
reverse(all(H));
for (int i = 0; i < SZ(H); ++i)
H[i] = 1ll * fac_inv[i] * KSM(KSM(n / 2, i), mod - 2) % mod * H[i] % mod;
return f * H;
}
int main() {
USE_CIN_COUT;
int n, a, b;
cin >> n >> a >> b;
if (a + b - 1 > n || a < 1 || b < 1) {
cout << 0 << '\n';
return 0;
}
fac[0] = fac[1] = fac_inv[0] = 1;
for (int i = 2; i <= n; ++i)
fac[i] = 1ll * fac[i - 1] * i % mod;
fac_inv[n] = KSM(fac[n], mod - 2);
for (int i = n - 1; i >= 1; --i)
fac_inv[i] = 1ll * fac_inv[i + 1] * (i + 1) % mod;
auto f = solve(n - 1);
auto ans = 1ll * f[a + b - 2] * fac[a + b - 2] % mod * fac_inv[a - 1] % mod * fac_inv[b - 1] % mod;
cout << ans << '\n';
return 0;
}