注意到每层的 G 都是相同的,并且 F 的初始状态是零次项为 1 的零次多项式,可以考虑直接倍增求 G 的幂。
时间复杂度 O(nlog2n).
注意代码和题解不符(dp 两维交换顺序)
代码
#include<cstdio>#include<algorithm>usingnamespace std;
typedeflonglong ll;
constint maxn = 4e5 + 5;
constint mod = 998244353;
constint g = 3;
int n, m;
int rev[maxn], fac[maxn], invf[maxn];
ll G[maxn], wp[maxn], bs[maxn], pw[maxn];
ll qpow(ll base, ll power, ll mod){
ll res = 1;
while (power)
{
if (power & 1) res = res * base % mod;
base = base * base % mod;
power >>= 1;
}
return res;
}
voidcalc_rev(int k){ for (int i = 1; i < k; i++) rev[i] = (rev[i >> 1] >> 1 | (i & 1 ? k >> 1 : 0)); }
voidNTT(ll *A, int n){
calc_rev(n);
for (int i = 1; i < n; i++)
if (rev[i] > i) swap(A[i], A[rev[i]]);
for (int len = 2, m = 1; len <= n; m = len, len <<= 1)
{
ll wn = qpow(g, (mod - 1) / len, mod);
wp[0] = 1;
for (int i = 1; i <= len; i++) wp[i] = wp[i - 1] * wn % mod;
for (int l = 0, r = len - 1; r <= n; l += len, r += len)
{
int w = 0;
for (int p = l; p < l + m; p++, w++)
{
ll x = A[p], y = wp[w] * A[p + m] % mod;
A[p] = (x + y) % mod, A[p + m] = (x - y + mod) % mod;
}
}
}
}
voidINTT(ll *A, int n){
NTT(A, n);
reverse(A + 1, A + n);
int inv = qpow(n, mod - 2, mod);
for (int i = 0; i < n; i++) A[i] = 1ll * A[i] * inv % mod;
}
voidpowp(int n, int pwr, int m){
int k = 1;
while (k < n) k <<= 1;
for (int i = 0; i <= m; i++) bs[i] = invf[i];
for (int i = m + 1; i < k; i++) bs[i] = 0;
pw[0] = 1; for (int i = 1; i < k; i++) pw[i] = 0;
while (pwr)
{
if (pwr & 1)
{
NTT(pw, k), NTT(bs, k);
for (int i = 0; i < k; i++) pw[i] = pw[i] * bs[i] % mod;
INTT(pw, k), INTT(bs, k);
for (int i = n; i < k; i++) pw[i] = 0;
}
NTT(bs, k);
for (int i = 0; i < k; i++) bs[i] = bs[i] * bs[i] % mod;
INTT(bs, k);
for (int i = n; i < k; i++) bs[i] = 0;
pwr >>= 1;
}
}
voidpowp(ll *F, int n, int pwr){
int k = 1;
while (k <= (n << 1)) k <<= 1;
for (int i = 0; i < n; i++) bs[i] = F[i];
for (int i = n; i < k; i++) bs[i] = 0;
pw[0] = 1; for (int i = 1; i < k; i++) pw[i] = 0;
while (pwr)
{
if (pwr & 1)
{
NTT(bs, k), NTT(pw, k);
for (int i = 0; i < k; i++) pw[i] = pw[i] * bs[i] % mod;
INTT(bs, k), INTT(pw, k);
for (int i = n; i < k; i++) pw[i] = 0;
}
NTT(bs, k);
for (int i = 0; i < k; i++) bs[i] = bs[i] * bs[i] % mod;
INTT(bs, k);
for (int i = n; i < k; i++) bs[i] = 0;
pwr >>= 1;
}
}
intsolve(int len, int n, int m){
if (m <= 0) return0;
int k = 1;
while (k < n) k <<= 1;
for (int i = 0; i <= m; i++) G[i] = invf[i];
for (int i = m + 1; i < k; i++) G[i] = 0;
powp(G, len + 1, n);
return pw[len] * fac[len] % mod;
}
intmain(){
scanf("%d%d", &n, &m);
fac[0] = invf[0] = fac[1] = invf[1] = 1;
for (int i = 2; i <= max(n, m); i++) fac[i] = 1ll * fac[i - 1] * i % mod, invf[i] = 1ll * (mod - mod / i) * invf[mod % i] % mod;
for (int i = 1; i <= max(n, m); i++) invf[i] = 1ll * invf[i - 1] * invf[i] % mod;
printf("%lld\n", (solve(n - 2, n, m - 1) - solve(n - 2, n, m - 2) + mod) % mod);
return0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· 三行代码完成国际化适配,妙~啊~
· .NET Core 中如何实现缓存的预热?
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?