首页 > 其他 > 详细

2017 四川 稀疏图生成树计数

时间:2019-10-05 14:55:05      阅读:183      评论:0      收藏:0      [点我收藏+]

Roads

In ICPCCamp there were $n$ towns conveniently numbered with $1, 2, \dots, n$ connected with $m$ roads.

Bobo would like to know the number of ways to keep only $(n - 1)$ roads so that the towns remain connected.

Note that the towns are connected if and only any two cities reach each other.

Input

The input contains zero or more test cases and is terminated by end-of-file. For each test case:

The first line contains two integers $n$ and $m$.

The $i$-th of the following $m$ lines contains two integers $a_i$ and $b_i$ which denotes a road between cities $a_i$ and $b_i$.

  • $1 \leq n \leq 10^5$
  • $n < m < n + 100$
  • $1 \leq a_i, b_i \leq n$
  • The towns are connected with $m$ roads.
  • The number of test cases does not exceed $10$.

Output

For each test case, output an integer which denotes the number of ways modulo $(10^9 + 7)$.

 

题解

#include <cassert>
#include <cstdio>
#include <vector>

// #define debug(...) fprintf(stderr, __VA_ARGS__)
#define debug(...)

const int MOD = (int)1e9 + 7;

void add(int& x, int a)
{
    x += a;
    if (x >= MOD) {
        x -= MOD;
    }
}

int inv(int a)
{
    return a == 1 ? 1 : 1LL * (MOD - MOD / a) * inv(MOD % a) % MOD;
}

int det(std::vector<std::vector<int>>& mat, int n)
{
    int result = 1;
    for (int j = 0; j < n; ++ j) {
        int pv = j;
        while (pv < n && mat.at(pv).at(j) == 0) {
            pv ++;
        }
        assert(pv < n);
        if (j < pv) {
            result = result * (MOD - 1LL) % MOD;
            std::swap(mat.at(j), mat.at(pv));
        }
        result = 1LL * result * mat.at(j).at(j) % MOD;
        int inv_ = inv(mat.at(j).at(j));
        for (int i = pv + 1; i < n; ++ i) {
            if (mat.at(i).at(j) != 0) {
                auto t = 1LL * inv_ * mat.at(i).at(j) % MOD;
                for (int k = j; k < n; ++ k) {
                    add(mat.at(i).at(k), MOD - mat.at(j).at(k) * t % MOD);
                }
            }
        }
    }
    return result;
}

int main()
{
    int n, m;
    while (scanf("%d%d", &n, &m) == 2) {
        std::vector<int> ends(m << 1);
        for (int i = 0; i < m << 1; ++ i) {
            scanf("%d", &ends.at(i));
            ends.at(i) --;
        }
        std::vector<std::vector<int>> graph(n);
        for (int i = 0; i < m << 1; ++ i) {
            graph.at(ends.at(i ^ 1)).push_back(i);
        }
        std::vector<int> degree(n), queue;
        for (int i = 0; i < n; ++ i) {
            degree.at(i) = graph.at(i).size();
            if (degree.at(i) == 1) {
                queue.push_back(i);
            }
        }
        for (int head = 0; head < static_cast<int>(queue.size()); ++ head) {
            auto u = queue.at(head);
            for (auto&& e : graph.at(u)) {
                auto&& v = ends.at(e);
                if ((degree.at(v) --) == 2) {
                    queue.push_back(v);
                }
            }
        }
        for (auto&& v : queue) {
            debug("%d, ", v + 1);
        }
        debug("queue\n");
        int nn = 0;
        std::vector<int> new_label(n, -1), neighbour(n, 1);
        for (int i = 0; i < n; ++ i) {
            if (degree.at(i) == 2) {
                for (auto&& e : graph.at(i)) {
                    if (degree.at(ends.at(e)) > 1) {
                        neighbour.at(i) ^= e;
                    }
                }
            }
            if (degree.at(i) > 2) {
                new_label.at(i) = nn ++;
            }
        }
        debug("n = %d\n", nn);
        for (int i = 0; i < n; ++ i) {
            debug("%d, ", degree.at(i));
        }
        debug("degree\n");
        int multiplier = 1;
        std::vector<std::vector<int>> laplacian(nn, std::vector<int>(nn));
        for (int s = 0; s < n; ++ s) {
            if (~new_label.at(s)) {
                for (auto&& se : graph.at(s)) {
                    if (degree.at(ends.at(se)) > 1) {
                        int e = se;
                        int t = ends.at(e);
                        int count = 1;
                        while (new_label.at(t) == -1) {
                            assert(degree.at(t) == 2);
                            e ^= neighbour.at(t);
                            t = ends.at(e);
                            count ++;
                        }
                        if (se <= (e ^ 1)) {
                            auto&& a = new_label.at(s);
                            auto&& b = new_label.at(t);
                            multiplier = 1LL * multiplier * count % MOD;
                            if (a != b) {
                                int weight = inv(count);
                                add(laplacian.at(a).at(a), weight);
                                add(laplacian.at(b).at(b), weight);
                                add(laplacian.at(a).at(b), MOD - weight);
                                add(laplacian.at(b).at(a), MOD - weight);
                            }
                        }
                    }
                }
            }
        }
        printf("%d\n", 1LL * multiplier * det(laplacian, nn - 1) % MOD);
    }
}

 

2017 四川 稀疏图生成树计数

原文:https://www.cnblogs.com/Aragaki/p/11624610.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!