zoukankan      html  css  js  c++  java
  • AtCoder NOMURA 2020 D

    首先, 一种情况下的答案就是 (n~-) 联通块数.
    要算所有情况下联通块数的和, 可以对于每个联通块单独考虑它出现的方案数再加起来.
    于是我们可以对于每个联通块选择一个 代表点, 对于这些代表点计数即可.
    将原图除 (-1) 之外的边连上, 将会是基环内向树和树的混合森林, 我们可以将基环树的环作为代表点.
    注意到树的根节点的 (p)(-1), 而基环树没有 (p)(-1) 的节点.
    先对基环树统计方案数. 考虑到它不可能再向外连边, 那么它成为连通块代表点的方案就是 ((N-1)^K).
    然后对含有 -1 的树结构计数: 考虑最终一个连通块中的环, 假设它是由大小为 (a_1,a_2,dots,a_m) 的树连成的, 那么它对答案的贡献就是 ((prod{a_i})(i-1)!(N-1)^{K-i}) (注意当 (m=1) 时贡献为 ((a_i-1)(N-1)^{K-1})). 由于一共有 (K) 个这样的树, 所以这部分的贡献要用 DP 来算.
    最终将两部分贡献加起来就是所有关键点(即所有连通块)贡献, 用 (N(N-1)^K) 减一下就是答案.

    #include <bits/stdc++.h>
    #define N 5050
    using namespace std;
    const int mod = 1e9 + 7;
    
    int fsp(int x, int k = mod - 2) {
        int res = 1;
        while (k) {
            if (k & 1) res = 1ll * res * x % mod;
            x = 1ll * x * x % mod, k >>= 1;
        }
        return res;
    }
    
    int n, p[N], sz[N], f[N][N], vis[N], t;
    vector<int> G[N];
    
    void dfs(int u, int r) {
        vis[u] = 1;
        if (r < 0) sz[-r]++;
        for (int v : G[u])
            if (v != r) dfs(v, r);
            else ++t;
    }
    
    int main() {
        cin >> n;
        for (int i = 1; i <= n; ++i) {
            scanf("%d", p + i);
            if (~p[i]) G[p[i]].push_back(i);
        }
    
        int K = 0;
        for (int i = 1; i <= n; ++i)
            if (p[i] == -1) dfs(i, -(++K));
        for (int i = 1; i <= n; ++i)
            if (!vis[i]) dfs(i, i);
    
        int ans = 1ll * t * fsp(n - 1, K) % mod;
    
        f[0][0] = 1;
        for (int i = 1; i <= K; ++i) {
            f[i][0] = 1;
            for (int j = 1; j <= i; ++j)
                f[i][j] = (f[i - 1][j] + 1ll * f[i - 1][j - 1] * sz[i]) % mod;
        }
    
        if (K) ans = (ans + 1ll * (f[K][1] - K) * fsp(n - 1, K - 1)) % mod;
        for (int i = 2, j = 1; i <= K; ++i) {
            j = 1ll * j * (i - 1) % mod;
            ans = (ans + 1ll * f[K][i] * j % mod * fsp(n - 1, K - i)) % mod;
        }
    
        ans = (1ll * n * fsp(n - 1, K) - ans) % mod;
        if (ans < 0) ans += mod;
        cout << ans << endl;
    
        return 0;
    }
    
  • 相关阅读:
    mysql索引
    springboot mybatis 后台框架平台 shiro 权限 集成代码生成器
    java 企业网站源码模版 有前后台 springmvc SSM 生成静态化
    java springMVC SSM 操作日志 4级别联动 文件管理 头像编辑 shiro redis
    activiti工作流的web流程设计器整合视频教程 SSM和独立部署
    .Net Core中的ObjectPool
    文件操作、流相关类梳理
    .Net Core中的配置文件源码解析
    .Net Core中依赖注入服务使用总结
    消息中间件RabbitMQ(一)
  • 原文地址:https://www.cnblogs.com/hnfms-jerry/p/solution_ATC_NOMURA2020_D.html
Copyright © 2011-2022 走看看