AT2064 [AGC005F] Many Easy Problems

https://www.luogu.com.cn/problem/AT2064

考虑每个点 u u u对答案的贡献
对于一个 k k k
先把 u u u设为根
那么它的对答案的贡献就是

( n k ) − ∑ v ∈ s o n [ u ] ( s i z e [ v ] k ) \binom{n}{k}-\sum_{v\in son[u]}\binom{size[v]}{k} (kn)vson[u](ksize[v])
然后发现和具体这个节点是什么没有啥关系,只与 s i z e [ v ] size[v] size[v]有关
所以把这个所有儿子的 s i z e size size n − s i z e [ u ] n-size[u] nsize[u]丢进桶里就行了

枚举 s i z e size size的大小
a n s [ k ] = n ( n k ) − ∑ i = k n c n t [ i ] ( i k ) ans[k]=n\binom{n}{k}-\sum_{i=k}^{n}cnt[i]\binom{i}{k} ans[k]=n(kn)i=kncnt[i](ki)

然后把后面那坨组合数拆开

1 k ! ∑ i = k n c n t [ i ] ∗ i ! × ( i − k ) ! \frac{1}{k!}\sum_{i=k}^n cnt[i]*i!\times(i-k)! k!1i=kncnt[i]i!×(ik)!
把下标改一下
1 k ! ∑ i = 0 n − k c n t [ i + k ] ∗ ( i + k ) ! × i ! \frac{1}{k!}\sum_{i=0}^{n-k} cnt[i+k]*(i+k)!\times i! k!1i=0nkcnt[i+k](i+k)!×i!

f [ i ] = c n t [ i ] ∗ i ! , g [ i ] = i ! f[i]=cnt[i]*i!,g[i]=i! f[i]=cnt[i]i!,g[i]=i!
然后把 f f f翻转一下来求差卷积即可

代码不难

code:

#include<bits/stdc++.h>
#define N 800050
#define mod 924844033
using namespace std;
int add(int x, int y) { x += y;
    if(x >= mod) x -= mod;
    return x;
}
int sub(int x, int y) { x -= y;
    if(x < 0) x += mod;
    return x;
}
int mul(int x, int y) {
    return 1ll * x * y % mod;
}
int qpow(int x, int y) {
    int ret = 1;
    for(; y; y >>= 1, x = mul(x, x)) if(y & 1) ret = mul(ret, x);
    return ret;
}

const int G = 5;
const int Ginv = qpow(G, mod - 2);
int rev[N];
void ntt(int *a, int n, int o) {
    for(int i = 1; i < n; i ++) rev[i] = (rev[i >> 1] >> 1) | ((i & 1) * (n >> 1));
    for(int i = 0; i < n; i ++) if(rev[i] > i) swap(a[i], a[rev[i]]);

    for(int len = 2; len <= n; len <<= 1) {
        int w0 = qpow((o == 1)? G : Ginv, (mod - 1) / len);
        for(int j = 0; j < n; j += len) {
            int wn = 1;
            for(int k = j; k < j + (len >> 1); k ++, wn = mul(wn, w0)) {
                int X = a[k], Y = mul(wn, a[k + (len >> 1)]);
                a[k] = add(X, Y), a[k + (len >> 1)] = sub(X, Y);
            }
        }
    }
    int ninv = qpow(n, mod - 2);
    if(o == -1) for(int i = 0; i < n; i ++) a[i] = mul(a[i], ninv);
}
struct edge {
    int v, nxt;
} e[N << 1];
int p[N], eid;
void init() {
    memset(p, -1, sizeof p);
    eid = 0;
}
void insert(int u, int v) {
    e[eid].v = v;
    e[eid].nxt = p[u];
    p[u] = eid ++;
}
int siz[N], cnt[N], n;
void dfs(int u, int fa) {
    siz[u] = 1;
    for(int i = p[u]; i + 1; i = e[i].nxt) {
        int v = e[i].v;
        if(v == fa) continue;
        dfs(v, u); siz[u] += siz[v];
        cnt[siz[v]] ++;
    }
    cnt[n - siz[u]] ++;
}
int fac[N], ifac[N];
void init(int n) {
    fac[0] = 1;
    for(int i = 1; i <= n; i ++) fac[i] = mul(fac[i - 1], i);
    ifac[n] = qpow(fac[n], mod - 2);
    for(int i = n - 1; i >= 0; i --) ifac[i] = mul(ifac[i + 1], i + 1);
}
int C(int x, int y) {
    if(x < y) return 0;
    return mul(fac[x], mul(ifac[y], ifac[x - y]));
}
int f[N], g[N];
int main() {
    init();
    scanf("%d", &n);
    for(int i = 1; i < n; i ++) {
        int u, v;
        scanf("%d%d", &u, &v);
        insert(u, v), insert(v, u);
    }
    dfs(1, 1); init(n);
    for(int i = 1; i <= n; i ++) f[i] = mul(cnt[i], fac[i]);
    for(int i = 0; i <= n; i ++) g[i] = ifac[i];
    reverse(f, f + 1 + n);
    int len = 1;
    for(; len <= n + n; len <<= 1);
    ntt(f, len, 1), ntt(g, len, 1);
    for(int i = 0; i < len; i ++) f[i] = mul(f[i], g[i]);
    ntt(f, len, - 1);
    reverse(f, f + 1 + n);
    for(int k = 1; k <= n; k ++) {
        printf("%d\n", sub(mul(n, C(n, k)), mul(ifac[k], f[k])));
    }
    return 0;
}
posted @ 2021-10-18 20:19  lahlah  阅读(34)  评论(0编辑  收藏  举报