由于要算的是概率,所以要算的东西分成两个部分 :所有情况的答案总和 和 情况数量。
考虑一层积木的 EGF
:(G(x) = e^x - 1)
那么 (k) 层积木的 EGF
就是 ((e^x - 1)^k)
我们要算的第二个东西的 EGF
就是 (sumlimits_{i = 1}^{n} G(x)^k = frac{G(x)^{n + 1} - G(x)}{G(x) - 1} equiv frac{G(x)}{G(x) - 1})。多项式求逆即可。
我们要算的第一个东西的是 EGF
是 (sumlimits_{i = 1}^n i G(x)^i)
[sumlimits_{i = 1}^n sumlimits_{j=1}^{i} G(x)^i
]
[sumlimits_{j=1}^{n} sumlimits_{i = j}^n G(x)^i
]
[sumlimits_{j=1}^{n} frac{G(x)^{n + 1} - G(x)^j}{G(x) - 1}
]
考虑到 (G(x)^{n + 1} equiv 0),所以是
[- frac{1}{G(x) - 1} sumlimits_{j=1}^{n} G(x)^j
]
[- frac{1}{G(x) - 1} frac{G(x)^{n + 1} - G(x)}{G(x) - 1}
]
[- frac{1}{G(x) - 1} frac{G(x)^{n + 1} - G(x)}{G(x) - 1}
]
[frac{G(x)}{(G(x) - 1)^2}
]
代码:
#include<bits/stdc++.h>
#define L(i, j, k) for(int i = j, i##E = k; i <= i##E; i++)
#define R(i, j, k) for(int i = j, i##E = k; i >= i##E; i--)
#define ll long long
#define ull unsigned long long
#define db double
#define pii pair<int, int>
#define mkp make_pair
using namespace std;
const int mod = 998244353, G = 3, iG = (mod + 1) / G, N = 3e5, MAXN = 1e5;
int qpow(int x, int y = mod - 2) {
int res = 1;
for(; y; x = (ll) x * x % mod, y >>= 1) if(y & 1) res = (ll) res * x % mod;
return res;
}
int lim, pp[N];
void poinit() { L(i, 0, lim - 1) pp[i] = ((pp[i >> 1] >> 1) | ((i & 1) * (lim >> 1))); }
void up(int len) { lim = 1; for(; lim <= len; lim <<= 1); }
void NTT(int *f, int flag) {
L(i, 0, lim - 1) if(pp[i] < i) swap(f[pp[i]], f[i]);
for(int i = 2; i <= lim; i <<= 1)
for(int j = 0, l = (i >> 1), ch = qpow(flag == 1 ? G : iG, (mod - 1) / i); j < lim; j += i) {
for(int k = j, now = 1; k < j + l; k ++) {
int pa = f[k], pb = (ll) f[k + l] * now % mod;
f[k] = (pa + pb) % mod, f[k + l] = (pa - pb + mod) % mod, now = (ll) now * ch % mod;
}
}
if(flag == -1) {
int ilim = qpow(lim);
L(i, 0, lim - 1) f[i] = (ll) f[i] * ilim % mod;
}
}
int sav[N];
void cle(int *f) { fill(f, f + lim, 0); }
void inv(int *f, int *g, int len) {
if(len == 1) return g[0] = qpow(f[0]), void();
inv(f, g, (len + 1) >> 1), up(len << 1), poinit(), cle(sav), copy(f, f + len, sav), NTT(sav, 1), NTT(g, 1);
L(i, 0, lim - 1) g[i] = (ll) g[i] * (2 + mod - (ll) sav[i] * g[i] % mod) % mod;
NTT(g, -1), fill(g + len, g + lim, 0);
}
int fac[N], ifac[N];
void minit(int x) {
fac[0] = 1;
L(i, 1, x) fac[i] = (ll) fac[i - 1] * i % mod;
ifac[x] = qpow(fac[x]);
R(i, x, 1) ifac[i - 1] = (ll) ifac[i] * i % mod;
}
int g[N], f[N], ans[N];
int main() {
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
minit(MAXN);
L(i, 0, MAXN) g[i] = ifac[i];
g[0] = mod - 1, inv(g, ans, MAXN + 1), g[0] = 0, up(MAXN * 2), poinit(), NTT(ans, 1), NTT(g, 1);
L(i, 0, lim - 1) f[i] = mod - (ll) g[i] * ans[i] % mod, ans[i] = (ll) ans[i] * ans[i] % mod;
NTT(f, -1), NTT(ans, -1), fill(ans + MAXN + 1, ans + lim, 0), NTT(ans, 1);
L(i, 0, lim - 1) ans[i] = (ll) ans[i] * g[i] % mod;
NTT(ans, -1);
int T, n; cin >> T;
while(T--) cin >> n, cout << (ll) ans[n] * qpow(f[n]) % mod << endl;
return 0;
}