「HNOI2004」树的计数

传送门

\(prufer\) 序列入门题。。。

首先特判掉 \(n = 1\) 的情况:度数为 \(0\) 则有唯一解,否则无解。

然后特判掉总度数不为 \(2(n - 1)\) 的情况:无解。

再特判一下出现度数为 \(0\) 的点,也就是树不连通的情况。

特判掉这些之后,就可以直接套公式了。。。

\[ans = \frac{(n - 2)!}{\prod_{i = 1} ^ n(d_i - 1)!} \]

如果不想用组合数来简化式子的话就直接 rush 高精吧

参考代码:

#include <cstdio>
#include <vector>
using namespace std;

int n, d[233];

struct BigInteger {
    vector < int > s;
    BigInteger() { s.clear(); }
    BigInteger clean() { while (s.size() && !s.back()) s.pop_back(); return *this; }
    BigInteger operator = (int x) {
        s.clear();
        while (x) s.push_back(x % 10), x /= 10;
        return this -> clean();
    }
    BigInteger operator * (const int& x) {
        int g = 0;
        for (int i = 0; i < s.size(); ++i) s[i] *= x;
        for (int i = 0; i < s.size(); ++i)
            s[i] += g, g = s[i] / 10, s[i] %= 10;
        while (g) s.push_back(g % 10), g /= 10;
        return this -> clean();
    }
    BigInteger operator / (const int& x) {
        int g = 0;
        for (int i = s.size() - 1; i >= 0; --i) {
            g = g * 10 + s[i];
            if (g >= x) s[i] = g / x, g %= x; else s[i] = 0;
        }
        return this -> clean();
    }
    void output() { for (int i = s.size() - 1; i >= 0; --i) printf("%d", s[i]); puts(""); }
} ans;

int main() {
#ifndef ONLINE_JUDGE
    freopen("cpp.in", "r", stdin), freopen("cpp.out", "w", stdout);
#endif
    scanf("%d", &n);
    int sum = 0;
    for (int i = 1; i <= n; ++i) scanf("%d", d + i), sum += d[i];
    if (n == 1) { puts(d[1] == 0 ? "1" : "0"); return 0; }
    if (sum != 2 * n - 2) { puts("0"); return 0; }
    for (int i = 1; i <= n; ++i)
        if (d[i] == 0) { puts(n == 1 ? "1" : "0"); return 0; }
    ans = 1;
    for (int i = 1; i <= n - 2; ++i) ans = ans * i;
    for (int i = 1; i <= n; ++i)
        for (int j = 1; j <= d[i] - 1; ++j) ans = ans / j;
    ans.output();
    return 0;
}
posted @ 2020-06-11 22:11  Sangber  阅读(167)  评论(0编辑  收藏  举报