有標號的二分圖計數 [生成函式 多項式]

Candy?發表於2017-05-03

有標號的二分圖計數

題目也在COGS上

[HZOI 2015]有標號的二分圖計數 I

[HZOI 2015]有標號的二分圖計數 II

[HZOI 2015]有標號的二分圖計數 III


I

求n個點的二分圖(可以不連通)的個數。\(n \le 10^5\)

其中二分圖進行了黑白染色,兩個二分圖不同:邊不同 或 點的顏色不同

水題啊,只有黑白之間連邊。
\[ \sum_{k=0}^n \binom{n}{k} 2^{k(n-k)} \]


II

求n個點的二分圖(可以不連通)的個數。\(n \le 10^5\)

不能簡單的除以2,問題在於有的黑白之間不連邊

i個連通塊,貢獻就是\(2^i\)

DP \(f(n,i)\)表示n個點i個連通塊的二分圖個數,\(O(n^3)\)

考慮生成函式

\(S(x)\)表示上道題,\(F(x)\)表示本題

還是不好做,因為都與連通塊有關,引入\(H(x)\)表示單個連通塊!
\[ S(x) = \sum_{i \ge 0} \frac{2^i \cdot H(x)^i}{i!} \\ F(x) = \sum_{i \ge 0} \frac{H(x)^i}{i!} = \sqrt{S(x)}\\ \]
多項式開根即可


III

求n個點的二分圖(必須連通)的個數。\(n \le 10^5\)

就是\(H(x)\)

就是\(\frac{1}{2} \ln S(x)\)


Code

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
typedef long long ll;
const int N = 1e5+5, P = 998244353;
inline int read() {
    char c=getchar();int x=0,f=1;
    while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
    return x*f;
}

ll Pow(ll a, int b) {
    ll ans = 1;
    for(; b; b>>=1, a=a*a%P)
        if(b&1) ans=ans*a%P;
    return ans;
}
int n;
ll inv[N], fac[N], facInv[N];
inline ll C(int n, int m) {return fac[n] * facInv[m] %P * facInv[n-m] %P;}
int main() {
    freopen("QAQ_bipartite_one.in", "r", stdin);
    freopen("QAQ_bipartite_one.out", "w", stdout);
    //freopen("in", "r", stdin);
    n = read();
    inv[1] = fac[0] = facInv[0] = 1;
    for(int i=1; i<=n; i++) {
        if(i != 1) inv[i] = (P - P/i) * inv[P%i] %P;
        fac[i] = fac[i-1] * i %P;
        facInv[i] = facInv[i-1] * inv[i] %P;
    }
    ll ans = 0;
    for(int k=0; k<=n; k++) ans = (ans + C(n, k) * Pow(2, (ll) k * (n-k) % (P-1))) %P;
    printf("%lld\n", ans);
}

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
typedef long long ll;
const int N = (1<<18) + 5, P = 998244353, qr2 = 116195171, inv2 = (P+1)/2;
inline int read() {
    char c=getchar();int x=0,f=1;
    while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
    return x*f;
}

ll Pow(ll a, int b) {
    ll ans = 1;
    for(; b; b >>= 1, a = a * a %P)
        if(b & 1) ans = ans * a %P;
    return ans;
}

namespace fft {
    int rev[N];
    void dft(int *a, int n, int flag) { 
        int k = 0; while((1<<k) < n) k++;
        for(int i=0; i<n; i++) {
            rev[i] = (rev[i>>1]>>1) | ((i&1)<<(k-1));
            if(i < rev[i]) swap(a[i], a[rev[i]]);
        }
        for(int l=2; l<=n; l<<=1) {
            int m = l>>1;
            ll wn = Pow(3, flag == 1 ? (P-1)/l : P-1-(P-1)/l);
            for(int *p = a; p != a+n; p += l) 
                for(int k=0, w=1; k<m; k++, w = w*wn%P) {
                    int t = (ll) w * p[k+m] %P;
                    p[k+m] = (p[k] - t + P) %P;
                    p[k] = (p[k] + t) %P;
                }
        }
        if(flag == -1) {
            ll inv = Pow(n, P-2);
            for(int i=0; i<n; i++) a[i] = a[i] * inv %P;
        }
    }

    void sqr(int *a, int n) {
        dft(a, n, 1);
        for(int i=0; i<n; i++) a[i] = (ll) a[i] * a[i] %P;
        dft(a, n, -1);
    }

    void inverse(int *a, int *b, int l) {
        static int t[N];
        if(l == 1) {b[0] = Pow(a[0], P-2); return;}
        inverse(a, b, l>>1);
        int n = l<<1;
        for(int i=0; i<l; i++) t[i] = a[i], t[i+l] = 0; 
        dft(t, n, 1); dft(b, n, 1);
        for(int i=0; i<n; i++) b[i] = (ll) b[i] * (2 - (ll) t[i] * b[i] %P + P) %P;
        dft(b, n, -1); for(int i=l; i<n; i++) b[i] = 0;
    }

    void sqrt(int *a, int *b, int l) {
        static int t[N], ib[N];
        if(l == 1) {b[0] = 1; return;}
        sqrt(a, b, l>>1);
        int n = l<<1;
        for(int i=0; i<l; i++) t[i] = a[i], t[i+l] = ib[i] = ib[i+l] = 0;
        inverse(b, ib, l);
        dft(t, n, 1); dft(b, n, 1); dft(ib, n, 1);
        for(int i=0; i<n; i++) b[i] = (ll) inv2 * (b[i] + (ll) t[i] * ib[i] %P) %P;
        dft(b, n, -1); for(int i=l; i<n; i++) b[i] = 0;
    }
}

int n, a[N], f[N], len;
ll inv[N], fac[N], facInv[N], mi[N];
int main() {
    //freopen("in", "r", stdin);
    freopen("QAQ_bipartite_two.in", "r", stdin);
    freopen("QAQ_bipartite_two.out", "w", stdout);
    n = read();
    len = 1; while(len <= n) len <<= 1;
    inv[1] = fac[0] = facInv[0] = 1;
    for(int i=1; i<=n; i++) {
        if(i != 1) inv[i] = (P - P/i) * inv[P%i] %P;
        fac[i] = fac[i-1] * i %P;
        facInv[i] = facInv[i-1] * inv[i] %P;
    }

    for(int i=0; i<=n; i++) a[i] = facInv[i] * Pow(Pow(qr2, (ll) i * i %(P-1) ), P-2) %P;
    fft::sqr(a, len<<1);
    for(int i=0; i<=n; i++) a[i] = a[i] * Pow(qr2, (ll) i * i %(P-1)) %P;
    fft::sqrt(a, f, len);
    printf("%lld\n", (ll) f[n] * fac[n] %P);
}

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
typedef long long ll;
const int N = (1<<18) + 5, P = 998244353, qr2 = 116195171, inv2 = (P+1)/2;
inline int read() {
    char c=getchar();int x=0,f=1;
    while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
    return x*f;
}

ll Pow(ll a, int b) {
    ll ans = 1;
    for(; b; b >>= 1, a = a * a %P)
        if(b & 1) ans = ans * a %P;
    return ans;
}

ll inv[N], fac[N], facInv[N];
namespace fft {
    int rev[N];
    void dft(int *a, int n, int flag) { 
        int k = 0; while((1<<k) < n) k++;
        for(int i=0; i<n; i++) {
            rev[i] = (rev[i>>1]>>1) | ((i&1)<<(k-1));
            if(i < rev[i]) swap(a[i], a[rev[i]]);
        }
        for(int l=2; l<=n; l<<=1) {
            int m = l>>1;
            ll wn = Pow(3, flag == 1 ? (P-1)/l : P-1-(P-1)/l);
            for(int *p = a; p != a+n; p += l) 
                for(int k=0, w=1; k<m; k++, w = w*wn%P) {
                    int t = (ll) w * p[k+m] %P;
                    p[k+m] = (p[k] - t + P) %P;
                    p[k] = (p[k] + t) %P;
                }
        }
        if(flag == -1) {
            ll inv = Pow(n, P-2);
            for(int i=0; i<n; i++) a[i] = a[i] * inv %P;
        }
    }

    void sqr(int *a, int n) {
        dft(a, n, 1);
        for(int i=0; i<n; i++) a[i] = (ll) a[i] * a[i] %P;
        dft(a, n, -1);
    }

    void inverse(int *a, int *b, int l) {
        static int t[N];
        if(l == 1) {b[0] = Pow(a[0], P-2); return;}
        inverse(a, b, l>>1);
        int n = l<<1;
        for(int i=0; i<l; i++) t[i] = a[i], t[i+l] = 0; 
        dft(t, n, 1); dft(b, n, 1);
        for(int i=0; i<n; i++) b[i] = (ll) b[i] * (2 - (ll) t[i] * b[i] %P + P) %P;
        dft(b, n, -1); for(int i=l; i<n; i++) b[i] = 0;
    }

    void ln(int *a, int *b, int l) {
        static int da[N], ia[N];
        int n = l<<1;
        for(int i=0; i<n; i++) da[i] = ia[i] = 0;
        for(int i=0; i<l-1; i++) da[i] = (ll) (i+1) * a[i+1] %P;
        inverse(a, ia, l);
        dft(da, n, 1); dft(ia, n, 1);
        for(int i=0; i<n; i++) b[i] = (ll) da[i] * ia[i] %P;
        dft(b, n, -1);
        for(int i=l-1; i>0; i--) b[i] = (ll) inv[i] * b[i-1] %P; b[0] = 0;
        for(int i=l; i<n; i++) b[i] = 0;
    }
}

int n, a[N], f[N], len;
int main() {
    //freopen("in", "r", stdin);
    freopen("QAQ_bipartite_thr.in", "r", stdin);
    freopen("QAQ_bipartite_thr.out", "w", stdout);
    n = read();
    len = 1; while(len <= n) len <<= 1;
    inv[1] = fac[0] = facInv[0] = 1;
    for(int i=1; i<=len; i++) {
        if(i != 1) inv[i] = (P - P/i) * inv[P%i] %P;
        fac[i] = fac[i-1] * i %P;
        facInv[i] = facInv[i-1] * inv[i] %P;
    }

    for(int i=0; i<=n; i++) a[i] = facInv[i] * Pow(Pow(qr2, (ll) i * i %(P-1) ), P-2) %P;
    fft::sqr(a, len<<1);
    for(int i=0; i<=n; i++) a[i] = a[i] * Pow(qr2, (ll) i * i %(P-1)) %P;
    fft::ln(a, f, len);
    printf("%lld\n", f[n] * fac[n] %P * inv2 %P);
}

相關文章