zoukankan      html  css  js  c++  java
  • Graph 题解

    一、题目:


    二、思路:

    经典的图计数问题。在这里说明一下,由于笔者不会多项式全家桶,所以代码的时间复杂度是 (O(n^2)) 的。

    首先设 (g_i) 表示区分左部和右部、图不一定连通、含有 (i) 个点的方案数。则有 (g_i=sumlimits_{j=0}^idbinom{i}{j}3^{j(i-j)})

    注意,(dfrac{g_n}{2}) 不是最终的答案!细想一下,$g_n $ 表示将 (n) 个点分入可区分的两个集合,那么 (g_n/2) 表示将 (n) 个点分入不可区分的两个集合。比如说 (dfrac{g_2}{2}=4),分别代表了这四种情况:

    但是我们发现情况 1 和情况 2 代表了相同的图。

    (f_i) 表示不区分左部和右部、保证图是连通的、包含 (i) 个点的方案数。则有

    [f_i=dfrac{g_i}{2}-sumlimits_{j=1}^{i-1}dbinom{i-1}{j-1} imes f_j imes g_{i-j} ]

    用总方案数减去不连通的方案数。如何算出不连通的方案数呢?考虑枚举 1 号点所在连通块的大小 (j)。我们发现,“不区分左部和右部”(Leftrightarrow)“规定 1 号点所在‘部’为左部”。所以剩下的 (i-j) 个点仍要区分左右部。

    最后设 (h_i) 为包含 (i) 个点的黑白图的数量。则有

    [h_i=sumlimits_{j=1}^i dbinom{i-1}{j-1} imes f_{j} imes h_{i-j} ]

    三、代码;

    // 64分的代码
    #include <iostream>
    #include <cstdio>
    #include <ctime>
    #include <cstring>
    
    using namespace std;
    #define FILEIN(s) freopen(s, "r", stdin)
    #define FILEOUT(s) freopen(s, "w", stdout)
    #define mem(s, v) memset(s, v, sizeof s)
    
    inline int read(void) {
        int x = 0, f = 1; char ch = getchar();
        while (ch < '0' || ch > '9') { if (ch == '-') f = -1; ch = getchar(); }
        while (ch >= '0' && ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); }
        return f * x;
    }
    
    const int MOD = 998244353, MAXN = 7000;
    
    int factor[MAXN], facinv[MAXN], div2;
    int g[MAXN], f[MAXN], h[MAXN], N;
    
    inline int power(int a, int b) {
        int res = 1;
        for (; b; b >>= 1) {
            if (b & 1) res = 1LL * res * a % MOD;
            a = 1LL * a * a % MOD;
        }
        return res;
    }
    
    inline int C(int n, int m) {
        return 1LL * factor[n] * facinv[m] % MOD * facinv[n - m] % MOD;
    }
    
    inline void Add(int &a, int b) {
        a += b;
        if (a >= MOD) a -= MOD;
    }
    
    void prework(void) {
        factor[0] = 1;
        for (int i = 1; i <= N; ++ i)
            factor[i] = 1LL * factor[i - 1] * i % MOD,
    
        facinv[N] = power(factor[N], MOD - 2);
        for (int i = N - 1; i >= 0; -- i) facinv[i] = 1LL * facinv[i + 1] * (i + 1) % MOD;
        div2 = facinv[2];
    
        h[0] = 1;
        for (int i = 1; i <= N; ++ i) {
            g[i] = 2;
            for (int j = 1; j <= i - 1; ++ j) {
                Add(g[i], 1LL * C(i, j) * power(3, j * (i - j)) % MOD);
    
                Add(f[i], 1LL * f[j] * g[i - j] % MOD * C(i - 1, j - 1) % MOD);
    
                Add(h[i], 1LL * f[j] * C(i - 1, j - 1) % MOD * h[i - j] % MOD);
            }
    
            f[i] = (1LL * g[i] * div2 % MOD - f[i] + MOD) % MOD;
    
            Add(h[i], f[i]);
        }
    }
    
    int main() {
        FILEIN("graph.in"); FILEOUT("graph.out");
        N = read();
        prework();
        while (N --) printf("%d
    ", h[read()]);
        return 0;
    }
    
  • 相关阅读:
    warshall、
    简单的php单例再次理解
    windows操作系统,在phpstudy集成环境,安装redis扩展,并启用redis服务和客户端
    php单例模式相关知识
    jui结合ajax非表单提交刷新页面
    php截取想要的字符串
    xmlToArray和arrayToXml
    jquery时间戳转换成格式化时间
    腾讯地图调用获取经度纬度代码
    随机生成自定义位数英文字符串
  • 原文地址:https://www.cnblogs.com/little-aztl/p/14993285.html
Copyright © 2011-2022 走看看