題目
https://loj.ac/problem/2541
思路
如果直接算,分母會變
所以要考慮另外一種方法
對於一個已經刪過的,我們不把它從分母中剔除,但是,每一次的選擇需要一直選直到選了一個沒有被刪過的。
於是乎,就能容斥了:
用NTT分治優化揹包即可
代碼
#include <bits/stdc++.h>
using namespace std;
const int P = 998244353,N = 5e5 + 5;
int n,w[N],G[2] = { 3,332748118 },A[30][N],d[N],c,t,p,re[N],ans;
int X(int x) {
if (x >= P)
x -= P;
return x;
}
int K(int x,int y) {
int A = 1;
for (; y; y >>= 1,x = 1ll * x * x % P)
if (y & 1)
A = 1ll * A * x % P;
return A;
}
void Ntt(int *g,bool o) {
for (int i = 0; i < t; i++)
if (i < re[i])
swap(g[i],g[re[i]]);
for (int wn,i = 1; i < t; i <<= 1) {
wn = K(G[o],(P - 1) / (i << 1));
for (int x,y,j = 0; j < t; j += (i << 1))
for (int w = 1,k = 0; k < i; k++,w = 1ll * w * wn % P)
x = g[j + k],y = 1ll * w * g[i + j + k] % P,g[j + k] = X(x + y),
g[i + j + k] = X(x - y + P);
}
if (o)
for (int i = 0,v = K(t,P - 2); i < t; i++) g[i] = 1ll * v * g[i] % P;
}
void solve(int l,int r) {
if (l == r) {
d[++c] = w[l];
A[c][0] = 1;
A[c][w[l]] = -1;
for (int i = 1; i < w[l]; i++) A[c][i] = 0;
return;
}
int mid = (l + r) >> 1;
solve(l,mid);
solve(mid + 1,r);
int L = d[c - 1],R = d[c];
for (t = 1,p = 0; t <= L + R; t <<= 1,p++)
;
for (int i = 0; i < t; i++) re[i] = (re[i >> 1] >> 1) | ((i & 1) << (p - 1));
for (int i = L + 1; i < t; i++) A[c - 1][i] = 0;
for (int i = R + 1; i < t; i++) A[c][i] = 0;
Ntt(A[c - 1],0);
Ntt(A[c],0);
for (int i = 0; i < t; i++) A[c - 1][i] = 1ll * A[c - 1][i] * A[c][i] % P;
Ntt(A[c - 1],1);
d[--c] = L + R;
}
int main() {
scanf("%d",&n);
for (int i = 1; i <= n; i++) scanf("%d",&w[i]);
solve(2,n);
for (int i = 0; i <= d[1]; i++) ans = X(ans + X(1ll * w[1] * A[1][i] % P * K(i + w[1],P - 2) % P + P));
return printf("%d\n",ans),0;
}