「PKUWC2018」獵人殺

題目

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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章