bzoj3456: 城市规划 生成函数 多项式求逆 多项式求ln

bzoj3456: 城市规划

题目传送门

分析

方法1:算二次法

考虑一张 n n n点的有标号无向图的个数,显然一共 C n 2 C_n^2 Cn2条边,所以方案数是 g n = 2 C n 2 g_n=2^{C_n^2} gn=2Cn2
f i f_i fi表示 i i i个点的无向连通图,一种计数的套路是枚举标号为1的点的所在联通快大小,得到
g n = ∑ i = 1 n f i ⋅ C n − 1 i − 1 ⋅ g n − i g_n=\sum_{i=1}^nf_i\cdot C_{n-1}^{i-1}\cdot g_{n-i} gn=i=1nfiCn1i1gni
g n ( n − 1 ) ! = ∑ i = 1 n f i ( i − 1 ) ! ⋅ g n − i ( n − i ) ! \frac{g_n}{(n-1)!}=\sum_{i=1}^n\frac{f_i}{(i-1)!}\cdot \frac{g_{n-i}}{(n-i)!} (n1)!gn=i=1n(i1)!fi(ni)!gni
这是一个卷积的形式
G = ∑ g i i ! x i , F ( i ) = f i ( i − 1 ) ! x i , M ( i ) = g i ( i − 1 ) ! x i G=\sum \frac{g_i}{i!}x^i,F(i)=\frac{f_i}{(i-1)!}x^i, M(i)=\frac{g_i}{(i-1)! }x^i G=i!gixi,F(i)=(i1)!fixi,M(i)=(i1)!gixi
那么有
G ⋅ F = M G\cdot F = M GF=M
F = M ⋅ G − 1 F=M \cdot G^{-1} F=MG1
多项式求逆即可。

方法1:指数生成函数

具体可以看这里
搞出 G ( n ) G(n) G(n)的EGF
G ( x ) = ∑ 2 C i 2 x i ! G(x)=\sum2^{C_i^2}\frac{x}{i!} G(x)=2Ci2i!x
搞出 F ( n ) F(n) F(n)的EGF
F ( x ) = ∑ f i x i ! F(x)=\sum f_i\frac{x}{i!} F(x)=fii!x
根据指数生成函数的集合划分意义,可以得到
G ( x ) = e F ( x ) G(x)=e^{F(x)} G(x)=eF(x)
然后 F ( x ) = l n ( G ( x ) ) F(x)=ln(G(x)) F(x)=ln(G(x))
所以多项式求ln即可
具体方法是
d F d x = d G G ( x ) \frac{dF}{dx}=\frac{dG}{G(x)} dxdF=G(x)dG
然后
F ( x ) = ∫ d G G ( x ) F(x)=\int \frac{dG}{G(x)} F(x)=G(x)dG
求导->多项式求逆->积分即可。
式子退出来是和方法1一样样的

代码

#include<bits/stdc++.h>
const int N = 524288, P = 1004535809;
int ri() {
    char c = getchar(); int x = 0, f = 1; for(;c < '0' || c > '9'; c = getchar()) if(c == '-') f = -1;
    for(;c >= '0' && c <= '9'; c = getchar()) x = (x << 1) + (x << 3) - '0' + c; return x * f;
}
int fix(int x) {return (x >> 31 & P) + x;}
int add(int a, int b) {return a += b, a >= P ? a - P : a;}
int mul(int a, int b) {return 1LL * a * b % P;}
int Pow(int x, int k) {
    int r = 1;
    for(;k; x = mul(x, x), k >>= 1)
        if(k & 1)
            r = mul(r, x);
    return r;
}
int Inv(int x) {return Pow(x, P - 2);}
int n, L, InvL, R[N], w[N], f[N], g[N], G[N], F[N], dG[N];
namespace NTT {
    void Pre(int m) {
        int x = 0; L = 1;
        for(;(L <<= 1) < m; ++x) ;
        for(int i = 1;i < L; ++i) 
            R[i] = R[i >> 1] >> 1 | (i & 1) << x;
        int wn = Pow(3, (P - 1) / L); w[0] = 1;
        for(int i = 1;i < L; ++i)
            w[i] = mul(w[i - 1], wn);
        InvL = Inv(L);
    }
    void DFT(int *F) {
        for(int i = 0;i < L; ++i) 
            if(i < R[i])
                std::swap(F[i], F[R[i]]);
        for(int i = 1, d = L >> 1; i < L; i <<= 1, d >>= 1)
            for(int j = 0;j < L; j += i << 1) {
                int *l = F + j, *r = F + j + i, *p = w, tp;
                for(int k = i;k--; ++l, ++r, p += d)
                    tp = mul(*r, *p), *r = fix(*l - tp), *l = add(*l, tp);
            }
    }
}
void Inv(const int A[], int *B, int n) {
    static int C[N];
    B[0] = Inv(A[0]); int m = 2;
    for(; m >> 1 < n; m <<= 1) {
        NTT::Pre(m << 1);
        for(int i = 0;i < m; ++i)
            C[i] = A[i], C[i + m] = B[i + m] = 0;
        NTT::DFT(C); NTT::DFT(B);
        for(int i = 0;i < L; ++i)
            C[i] = mul(fix(2 - mul(C[i], B[i])), B[i]);
        NTT::DFT(C);
        for(int i = 0;i < m; ++i)
            B[i] = mul(C[L - i & L - 1], InvL), B[i + m] = 0;
    }
}
void Pre(int n) {
    f[0] = 1; for(int i = 1;i <= n; ++i) f[i] = mul(f[i - 1], i);
    g[n] = Inv(f[n]); for(int i = n; i; --i) g[i - 1] = mul(g[i], i);
}
int main() {
    Pre(n = ri()); G[1] = 1;
    for(int i = 0;i <= n; ++i)
        G[i] = mul(Pow(2, (1LL * i * (i - 1) >> 1) % (P - 1)), g[i]);
    for(int i = 1;i <= n; ++i)
        dG[i - 1] = mul(G[i], i);
    Inv(G, F, n + 1);
    Pre((n << 1) + 1);
    NTT::DFT(dG); NTT::DFT(F);
    for(int i = 0;i < L; ++i)
        F[i] = mul(F[i], dG[i]);
    NTT::DFT(F);
    printf("%d\n", mul(mul(F[L - n + 1 & L - 1], InvL), f[n - 1]));
    return 0;
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值