loj2541c++
題意概要:給定 \(n\) 我的的倒黴度 \(\{w_i\}\),每回合會有一我的死亡,每一個人這回合死亡的機率爲 本身的倒黴度
/目前全部存活玩家的倒黴度之和
,求第 \(1\) 我的最後一個死亡的機率git
設 \(B = \sum_{i=2}^nw_i\)函數
要求 \(1\) 號最後一個被選中有點很差作,可是求 \(1\) 號第一個被選中仍是比較好作的(\(\frac {w_1}{\sum_{i=1}^nw_i}\))spa
至於這二者怎麼聯繫起來,使用 \(\mathrm {min-max}\) 容斥(和 HAOI2015按位或 有點像:前者是求 \(1\) 號最後一個被選中的機率;後者是求集合內最後一個被選中的指望次數)code
\(\mathrm{min-max}\) 容斥的式子爲:ci
\[\max\{S\}=\sum_{T\subseteq S}(-1)^{|T|-1}\min\{T\}\]get
因爲 \(1\) 爲須要求的點,將其從 \(S,T\) 的定義中刨除,即it
\[\max\{S\}=\sum_{T\subseteq S}(-1)^{|T|}\min\{T\}\]io
而同時class
\[\min\{T\}=\frac {w_1}{w_1+\sum_{x\in T}w_i}\]
發現 \(\min\{T\}\) 最多有 \(B\) 種,能夠考慮計算出每一項的容斥係數再 \(O(B)\) 計算
至於計算容斥係數,可以使用母函數求得,即求出下面式子的每一項係數:
\[\prod_{i=2}^n(1-x^{w_i})\]
分治 ntt 求解,每一層母函數度數和爲 \(B\),複雜度 \(O(B\log B)\),總複雜度 \(O(B\log^2B)\)
#include <bits/stdc++.h> using namespace std; typedef long long ll; inline void read(int&x){ char ch=getchar();x=0;while(!isdigit(ch))ch=getchar(); while(isdigit(ch))x=x*10+ch-'0',ch=getchar(); } const int N = 200200, T = 37, p = 998244353; int stk[T], tp; int brr[T][N], L[T]; int w[N], rev[N]; inline int qm(const int&x) {return x < p ? x : x - p;} inline int qpow(int A, int B) { int res = 1; while(B) { if(B&1) res = (ll)res * A%p; A = (ll)A * A%p, B >>= 1; } return res; } void dft(int*a,int n,int sgn) { for(int i=1;i<n;++i) if(i < rev[i]) swap(a[i], a[rev[i]]); for(int i=1;i<n;i<<=1) { int gn = qpow(3, (p-1)/(i<<1)); for(int j=0;j<n;j+=(i<<1)) { int g = 1; for(int k=0;k<i;++k,g=(ll)g*gn%p) { int x = a[j+k], y = (ll)g * a[j+k+i]%p; a[j+k] = qm(x + y), a[j+k+i] = qm(x - y+p); } } } if(!sgn) { int iv = qpow(n, p-2); reverse(a+1,a+n); for(int i=0;i<n;++i) a[i] = (ll)a[i] * iv%p; } } void mul(int ai, int bi, int ci) { int*ar = brr[ai], *br = brr[bi], *cr = brr[ci]; int n = L[ai], m = L[bi], &t = L[ci]; t = n + m; int nn = 1, l = 0; while(nn < t) nn <<= 1, ++ l; for(int i=n;i<nn;++i) ar[i] = 0; for(int i=m;i<nn;++i) br[i] = 0; for(int i=1;i<nn;++i) rev[i] = (rev[i>>1]>>1) | ((i&1) << l-1); dft(ar, nn, 1), dft(br, nn, 1); for(int i=0;i<nn;++i) cr[i] = (ll)ar[i] * br[i]%p; dft(cr, nn, 0); } int binary(int l, int r) { if(l == r) { int id = stk[--tp], *arr = brr[id]; for(int i=w[l]<<1;i;--i) arr[i] = 0; arr[0] = 1, arr[w[l]] = p-1, L[id] = w[l]+1; return id; } int mid = l + r >> 1; int ls = binary(l, mid), rs = binary(mid+1, r); int id = stk[--tp]; mul(ls, rs, id); stk[tp++] = ls, stk[tp++] = rs; return id; } int main() { for(int i=0;i<T;++i) stk[tp++] = T-i-1; int n; read(n); for(int i=1;i<=n;++i) read(w[i]); int id = binary(2, n); int ans = 0, *arr = brr[id]; for(int i=0;i<L[id];++i) ans = (ans + (ll)arr[i] * qpow(w[1] + i, p-2))%p; ans = (ll)ans * w[1]%p; printf("%d\n",ans); return 0; }