sol
一道容斥题,要结合生成函数。
首先有个技巧:设猎人(i)还活着,他被开枪的概率为剩下猎人中按权值分配的概率,这样很麻烦,还需要知道剩余哪些人,其实等价于人都在,但被开枪到死人时要重新开枪的概率。因为对于活着的猎人,被开枪仍然概率不变。这点很重要,因为仍然可以用(p_i=dfrac{w_i}{tot})表示概率,其中(tot=sumlimits_j w_j)。
直接算出来(1)号猎人最后挂掉的概率很麻烦,考虑容斥。设集合(Ssubset{2,3,dots,n})表示猎人编号的集合,则可以容斥得到
[ans=1+sum_{S}(-1)^{mid Smid}Pr(S)
]
(Pr(S))表示挂在(1)号猎人后面至少为(S)中的猎人的概率。现在来分析这个东西,那么显然前面若干次一定是(overline S)中的人,除了(1)号被淘汰时立刻停止,否则继续。显然是一个无穷级数的求和。记(tot=sum w_i),(sum=sum_{iin S}w_i),那么有
[egin{aligned}
Pr(S)&=sum_{i=0}^inftyleft(dfrac{tot-sum-w_1}{tot}
ight)^i imes dfrac{w_1}{tot}\
&=dfrac{1}{1-dfrac{tot-sum-w_i}{tot}} imesdfrac{w_1}{tot}\
&=dfrac{w_1}{sum+w_1}
end{aligned}
]
那么上面的式子就变成
[ans=1+sum_S(-1)^{mid Smid}dfrac{w_1}{tot+w_1}
]
根据数据范围提示,转变枚举方式,考虑枚举(tot),这个与(S)有关,记(f(i)=sum_{tot=i}(-1)^{mid Smid}),那么式子就变成了
[ans=1+sum_{i}f(i)dfrac{w_1}{i+w_1}
]
问题就变成了求解(f)。使用生成函数构造出(f),令(F=prod(1-x^{w_i})),则(f(i)=[x^i]F(x))。至此问题得解。
#include <bits/stdc++.h>
using std::swap; using std::reverse;
typedef std::vector<int> Poly;
const int N = 100005, P = 998244353;
int n, w[N], L = 0;
int inc(int a, int b) { return (a += b) >= P ? a-P : a; }
int qpow(int a, int b) {
int t = 1;
for (; b; b >>= 1, a = 1LL*a*a%P)
if (b & 1) t = 1LL*t*a%P;
return t;
}
int W[N*2];
void prework(int n) {
for (int i = 1; i < n; i <<= 1)
for (int j = W[i] = 1, Wn = qpow(3, (P-1)/i>>1); j < i; j++)
W[i+j] = 1LL*W[i+j-1]*Wn%P;
}
void fft(Poly &a, int n, int op) {
a.resize(n);
static int rev[N*2];
for (int i = 1; i < n; i++)
if ((rev[i] = rev[i>>1]>>1|(i&1?n>>1:0)) > i) swap(a[i], a[rev[i]]);
for (int q = 1; q < n; q <<= 1)
for (int p = 0; p < n; p += q<<1)
for (int i = 0, t; i < q; i++)
t = 1LL*W[q+i]*a[p+q+i]%P, a[p+q+i] = inc(a[p+i], P-t), a[p+i] = inc(a[p+i], t);
if (op) return;
for (int i = 0, inv = qpow(n, P-2); i < n; i++) a[i] = 1LL*a[i]*inv%P;
reverse(a.begin()+1, a.end());
}
void fix(Poly &A) { int x = A.size(); while (x > 1 && !A[x-1]) x--; A.resize(x); }
int getsz(int n) { int x = 1; while (x < n) x <<= 1; return x; }
Poly operator * (Poly A, Poly B) {
int L = getsz(A.size() + B.size() - 1);
fft(A, L, 1), fft(B, L, 1);
for (int i = 0; i < L; i++) A[i] = 1LL*A[i]*B[i]%P;
return fft(A, L, 0), fix(A), A;
}
Poly A[N*4]; int ans = 0;
void build(int o, int l, int r) {
if (l == r) {
A[o] = Poly(w[l]+1); A[o][0] = P-1; A[o][w[l]] = 1;
return;
}
int mid = l+r>>1;
build(o<<1, l, mid), build(o<<1|1, mid+1, r);
A[o] = A[o<<1] * A[o<<1|1];
}
int main() {
scanf("%d", &n);
for (int i = 1; i <= n; i++) scanf("%d", &w[i]), L += w[i];
prework(L);
build(1, 2, n);
for (int i = 0; i < A[1].size(); i++)
ans = (ans + 1LL*A[1][i]*L%P*qpow(L-i, P-2)) % P;
ans = 1LL*ans*w[1]%P*qpow(L, P-2)%P;
printf("%d", ans);
return 0;
}