• 【题解】51nod 1806 wangyurzee的树


      看这道题目懵逼了好久, (m <= 17) 一眼容斥,然而并没有想到怎么求出生成树的个数。然后灵光一闪——我不是学过一个叫Prüfer编码的东西嘛?!那就完美解决啦~

      Prüfer编码就是将一棵无根树映射到一串编码上的编码方法,一棵 (n) 个节点的树与一个长度为 (n - 2) 的编码串一一对应。所以我们要求合法的 = 总数 (n ^ {n - 2}) - 不合法的方案数。不合法的方案数 = 至少有 (1) 个不合法 - 至少有 (2) 个不合法 + 至少有(3) 个不合法……有何求出至少有 (k) 个不合法的方案数呢?

      我们可以首先搜索出这 (k) 个限制(复杂度约为 (2^{17})),然后令这(k) 个限制的 (sum = sum d[i] - 1),(sum) 即为这 (k) 个限制中所牵涉到的节点在数列中一共应该出现的次数。满足这个限制(每一个节点出现 (d[i] - 1) 次)的数列个数即为 (frac{sum!}{prod (d[i] - 1)!})。又因为这 (sum) 个数可以出现在长度为 (n - 2) 的数列中的任何位置,所以 乘上(C(n - 2, sum)),剩下的 (n - 2 - sum) 个数则可以随便选择,有 ((n - k) ^ {n - sum - 2}) 种方案。完美~

    #include <bits/stdc++.h>
    using namespace std;
    #define maxn 2000000
    #define int long long
    #define mod 1000000007
    int n, m, fac[maxn];
    int cnt, tot = 1, Ans = 1, S[maxn];
    bool mark[maxn], vis[maxn];
    
    int read()
    {
        int x = 0, k = 1;
        char c;
        c = getchar();
        while(c < '0' || c > '9') { if(c == '-') k = -1; c = getchar(); }
        while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
        return x * k;
    }
    
    struct node
    {
        int x, d;
    }Q[maxn];
    
    int Qpow(int x, int timer)
    {
        int base = 1;
        for(; timer; timer >>= 1, x = x * x % mod)
            if(timer & 1) base = base * x % mod; 
        return base;
    }
    
    int C(int n, int m)
    { 
        if(m > n) return 0;
        return fac[n] * Qpow(fac[m], mod - 2) % mod * Qpow(fac[n - m], mod - 2) % mod; 
    }
    
    void Search(int now, int last)
    {
        if(m - last + 1 < now) return;
        if(!now)
        {
            int tem = 1, sum = 0;
            for(int i = 1; i <= cnt; i ++)
                tem = tem * (fac[Q[S[i]].d - 1]) % mod,
                sum += Q[S[i]].d - 1;
            if(sum > n - 2) return;
            tem = Qpow(tem, mod - 2); 
            tem = tem * fac[sum] % mod * C(n - 2, sum) % mod * Qpow(n - cnt, n - sum - 2) % mod; 
            if(cnt & 1) Ans = (Ans - tem + mod) % mod;
            else Ans = (Ans + tem) % mod;
            return;
        }
        for(int i = last; i <= m; i ++)
        {
            if(vis[Q[i].x]) continue;
            S[++ cnt] = i, vis[Q[i].x] = 1; Search(now - 1, i + 1);
            cnt --, vis[Q[i].x] = 0;
        }
    }
    
    signed main()
    {
        n = read(), m = read();
        for(int i = 1; i <= m; i ++)
            Q[i].x = read(), Q[i].d = read();
        if(n - 2 > 0) Ans = Qpow(n, n - 2);
        else
        {
            printf("1
    ");
            return 0;
        }
        fac[0] = 1;
        for(int i = 1; i <= n; i ++) fac[i] = fac[i - 1] * i % mod;
        for(int i = 1; i <= m; i ++) Search(i, 1);
        printf("%lld
    ", Ans);
        return 0;
    }
  • 相关阅读:
    2014-04-23 总结
    14-5-13
    PHP
    14-5-8
    ajax
    14-5-6
    14-5-5
    PHP初解
    14-4-30
    14-4-29
  • 原文地址:https://www.cnblogs.com/twilight-sx/p/9406260.html
Copyright © 2020-2023  润新知