题目
给一个正整数n和询问数q,每次询问给出两个数x和y,问有多少长度为n的排列P满足:
py=maxni=1pi
p
y
=
m
a
x
i
=
1
n
p
i
2px<py
2
p
x
<
p
y
n,q<10^5
分析
因为x只是一个位置,所以对于给定的y而言不同的x是不会对答案产生影响的。
所以我们只用考虑y就好了。
然后呢我们可以发现答案其实要我们求的就是这个式子:
然后我们就可以用ntt求解了。
代码
#include <bits/stdc++.h>
typedef long long ll;
const int N = 100010;
const int MOD = 998244353;
int read()
{
int x = 0, f = 1;
char ch = getchar();
while (ch < '0' || ch > '9') {if (ch == '-') f = -1; ch = getchar();}
while (ch >= '0' && ch <= '9') {x = x * 10 + ch - '0'; ch = getchar();}
return x * f;
}
int f[N * 4],g[N * 4],rev[N * 4];
int ny[N],jc[N];
int L,n,q;
int ksm(int x,int y)
{
int res = 1;
while (y)
{
if (y & 1)
res = 1ll * res * x % MOD;
x = 1ll * x * x % MOD;
y >>= 1;
}
return res;
}
void ntt(int *a, int f)
{
for (int i = 0; i < L; i++)
if (i < rev[i])
std::swap(a[i], a[rev[i]]);
for (int i = 1; i < L; i <<= 1)
{
int wn = ksm(3, f == 1 ? (MOD - 1) / i / 2 : MOD - 1 - (MOD - 1) / i / 2);
for (int j = 0; j < L; j += (i << 1))
{
int w = 1;
for (int k = 0; k < i; k++)
{
int u = a[j + k], v = 1ll * a[j + k + i] * w % MOD;
a[j + k] = (u + v) % MOD;
a[j + k + i] = (u + MOD - v) % MOD;
w = 1ll * w * wn % MOD;
}
}
}
int nyL = ksm(L, MOD - 2);
if (f == -1)
for (int i = 0; i < L; i++)
a[i] = 1ll * a[i] * nyL % MOD;
}
int main()
{
n = read(), q = read();
jc[0] = jc[1] = ny[0] = ny[1] = 1;
for (int i = 2; i <= n; i++)
jc[i] = 1ll * jc[i - 1] * i % MOD, ny[i] = 1ll * (MOD - MOD / i) * ny[MOD % i] % MOD;
for (int i = 2; i <= n; i++)
ny[i] = 1ll * ny[i - 1] * ny[i] % MOD;
for (int i = 3; i <= n; i++)
f[i] = 1ll * (i - 1) / 2 * jc[i - 2] % MOD;
for (int i = 0; i <= n; i++)
g[i] = ny[n - i];
int lg = 0;
for (L = 1; L <= n * 2; L <<= 1, lg++);
for (int i = 0; i < L; i++)
rev[i] = (rev[i >> 1] >> 1) | ((i & 1) << (lg - 1));
ntt(f, 1), ntt(g, 1);
for (int i = 0; i < L; i++)
f[i] = 1ll * f[i] * g[i] % MOD;
ntt(f, -1);
while (q--)
{
int x = read(), y = read();
printf("%d\n", 1ll * f[n + y] * jc[n - y] % MOD);
}
}