21牛客多校10 - Game of Death(思維,概率)
阿新 • • 發佈:2021-08-22
題目
G-Game of Death_2021牛客暑期多校訓練營10
題解
設\(f(S)\)代表集合\(S\)的人均被擊中概率,\(g(S)\)代表擊中的人是\(S\)的子集的概率。
可得
\[f(S)=\sum\limits_{T \subseteq S}{(-1)^{|S|-|T|}\cdot g(T)} \]由於所有相同大小的集合本質是一樣的,所有相同大小的集合的\(f\)和\(g\)概率均相同。所以可以將子集看作子集大小直接算,然後推式子即可。(g式子推導略)
\[f(i)=\sum\limits_{j\le i}{(-1)^{i-j}\cdot C(i,j) \cdot g(j)} \]可以直接卷積。
關鍵在於\(f\)和\(g\)的定義。
#include <bits/stdc++.h> #define endl '\n' #define IOS std::ios::sync_with_stdio(0); cin.tie(0); cout.tie(0) #define mp make_pair #define seteps(N) fixed << setprecision(N) typedef long long ll; using namespace std; /*-----------------------------------------------------------------*/ ll gcd(ll a, ll b) {return b ? gcd(b, a % b) : a;} #define INF 0x3f3f3f3f const int N = 2e6 + 10; const int M = 998244353; const double eps = 1e-5; inline ll qpow(ll a, ll b, ll m) { ll res = 1; while(b) { if(b & 1) res = (res * a) % m; a = (a * a) % m; b = b >> 1; } return res; } int rev[N]; void change(ll y[], int len) { for (int i = 0; i < len; ++i) { rev[i] = rev[i >> 1] >> 1; if (i & 1) { rev[i] |= len >> 1; } } for (int i = 0; i < len; ++i) { if (i < rev[i]) { swap(y[i], y[rev[i]]); } } return; } void fft(ll y[], int len, int on) { change(y, len); for (int h = 2; h <= len; h <<= 1) { ll gn = qpow(3, (M - 1) / h, M); if (on == -1) gn = qpow(gn, M - 2, M); for (int j = 0; j < len; j += h) { ll g = 1; for (int k = j; k < j + h / 2; k++) { ll u = y[k]; ll t = g * y[k + h / 2] % M; y[k] = (u + t) % M; y[k + h / 2] = (u - t + M) % M; g = g * gn % M; } } } if (on == -1) { ll inv = qpow(len, M - 2, M); for (int i = 0; i < len; i++) { y[i] = y[i] * inv % M; } } } int get(int x) { int res = 1; while (res < x) { res <<= 1; } return res; } ll p, rn; int n, a, b; ll G(ll x) { ll a = ((x - 1) + (n - x) * (1 - p) % M) * rn % M; ll b = (x + (n - x - 1) * (1 - p) % M) * rn % M; return qpow(a + M, x, M) * qpow(b + M, n - x, M) % M; } ll f[N], g[N]; ll fact[N], rfact[N]; ll C(int n, int m) { if(n < m) return 0; return fact[n] * rfact[n - m] % M * rfact[m] % M; } int main() { IOS; fact[0] = rfact[0] = 1; for(int i = 1; i < N; i++) { fact[i] = fact[i - 1] * i % M; rfact[i] = qpow(fact[i], M - 2, M); } cin >> n >> a >> b; p = a * qpow(b, M - 2, M) % M; rn = qpow(n - 1, M - 2, M); for(int i = 0; i <= n; i++) g[i] = G(i) * rfact[i] % M; for(int i = 0; i <= n; i++) f[i] = ((i % 2 ? -1 : 1) * rfact[i] % M + M) % M; int len = get(2 * (n + 1) + 1); fft(f, len, 1); fft(g, len, 1); for(int i = 0; i < len; i++) f[i] = f[i] * g[i] % M; fft(f, len, -1); for(int i = 0; i <= n; i++) { cout << fact[n - i] * C(n, n - i) % M * f[n - i] % M << endl; } }