• [LuoguP1829]Crash的文明表格(二次扫描与换根+第二类斯特林数)


    a.png

    Solution:

    ​ 由于

    [x^m = sum_{i=0}^m{~m~choose i}{~x~race i}i! ]

    ​ 将所求的式子化成这样,挖掘其性质,考虑是否能从儿子转移(或利用以求得信息)。

    [egin{aligned} S(u) &= sum_{i=1}^ndis(u,i)^k\ &= sum_{i=1}^nsum_{j=0}^k{dis(u, i) choose j}{krace j}j!\ &= sum_{j=0}^kj!{krace j}sum_{i=1}^n{dis(u, i)choose j} end{aligned} ]

    ​ 由于组合数有:({nchoose m} = {n - 1choose m - 1} + {n - 1choose m})

    ​ 而从儿子及父亲到自己的距离为1,于是可以考虑换根树型dp求出每个点的 (sum_{i=1}^n{dis(u, i)choose j})

    ​ 设 (f[u][j] = sum_{i}{dis(u, i) choose j}) 其中 (i)(u) 子树中的点。

    ​ 设 (g[u][j] = sum_{i=1}^n{dis(u, i)choose j})

    [f[u][j] = sum_{vin son(u)}f[v][j] + f[v][j - 1]\ g[u][j] = g[fa(u)][j-1]-f[u][j-2]-f[u][j-1]+g[fa(u)][j]-f[u][j-1]-f[u][j]+f[u][j] ]

    Code

    #include <vector>
    #include <cmath>
    #include <cstdio>
    #include <cassert>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    
    typedef long long LL;
    typedef unsigned long long uLL;
    
    #define fir first
    #define sec second
    #define SZ(x) (int)x.size()
    #define MP(x, y) std::make_pair(x, y)
    #define PB(x) push_back(x)
    #define debug(...) fprintf(stderr, __VA_ARGS__)
    #define GO debug("GO
    ")
    #define rep(i, a, b) for (register int i = (a), i##end = (b); (i) <= i##end; ++ (i))
    #define drep(i, a, b) for (register int i = (a), i##end = (b); (i) >= i##end; -- (i))
    #define REP(i, a, b) for (register int i = (a), i##end = (b); (i) < i##end; ++ (i))
    
    inline int read() {
        register int x = 0; register int f = 1; register char c;
        while (!isdigit(c = getchar())) if (c == '-') f = -1;
        while (x = (x << 1) + (x << 3) + (c xor 48), isdigit(c = getchar()));
        return x * f;
    }
    template<class T> inline void write(T x) {
        static char stk[30]; static int top = 0;
        if (x < 0) { x = -x, putchar('-'); }
        while (stk[++top] = x % 10 xor 48, x /= 10, x);
        while (putchar(stk[top--]), top);
    }
    template<typename T> inline bool chkmin(T &a, T b) { return a > b ? a = b, 1 : 0; }
    template<typename T> inline bool chkmax(T &a, T b) { return a < b ? a = b, 1 : 0; }
    
    using namespace std;
    
    const int maxN = 50004;
    const int maxK = 153;
    const int MOD = 10007;
    
    int n, k;
    int fac[maxK];
    int stirl[maxK][maxK];
    vector<int> ver[maxN];
    
    void Input()
    {
        n = read(), k = read();
        for (int i = 1; i < n; ++i)
        {
            int u = read(), v = read();
            ver[u].push_back(v);
            ver[v].push_back(u);
        }
    }
    
    void Init() 
    {
        fac[0] = 1;
        rep (i, 1, k) 
            fac[i] = 1ll * fac[i - 1] * i % MOD;
        stirl[0][0] = stirl[1][1] = 1;
        rep (i, 2, k)
            rep (j, 1, i) 
                stirl[i][j] = (1ll * stirl[i - 1][j - 1] + 1ll * j * stirl[i - 1][j] % MOD) % MOD;
    }
    
    int f[maxN][maxK], g[maxN][maxK], tmp[maxK];
    
    void dfs1(int u, int fa)
    {
        f[u][0] = 1;
        for (int v : ver[u]) 
            if (v != fa)
            {
                dfs1(v, u);
                f[u][0] = (1ll * f[u][0] + f[v][0]) % MOD;
                for (int j = 1; j <= k; ++j)
                    f[u][j] = ((1ll * f[u][j] + f[v][j]) % MOD + f[v][j - 1]) % MOD;
            }
    }
    
    void add(int &x, int y)
    {
        x = (1ll * x + y + MOD) % MOD;
    }
    
    void dfs2(int u, int fa)
    {
        if (!fa) 
            for (int i = 0; i <= k; ++i) g[u][i] = f[u][i];
        else 
        {
            g[u][0] = g[fa][0];
            for (int j = 1; j <= k; ++j)
            {
               int &x = g[u][j];
               x = 0;
               add(x, g[fa][j]);
               add(x, -f[u][j]);
               add(x, -f[u][j - 1]);
               add(x, g[fa][j - 1]);
               add(x, -f[u][j - 1]);
               add(x, f[u][j]);
               if (j >= 2) add(x, -f[u][j - 2]);
            }
        }
        for (int v : ver[u])
            if (v != fa)
                dfs2(v, u);
    }
    
    
    void Solve()
    {
        dfs1(1, 0);
        dfs2(1, 0);
        for (int i = 1; i <= n; ++i)
        {
            int ans = 0;
            for (int j = 0; j <= k; ++j)
                ans = (1ll * ans + 1ll * stirl[k][j] * fac[j] % MOD * g[i][j] % MOD) % MOD;
            cout << ans << endl;
        }
    }
    
    int main() 
    {
    #ifndef ONLINE_JUDGE
        freopen("tmp.in", "r", stdin);
        freopen("tmp.out", "w", stdout);
    #endif
    
        Input();
    
        Init();
    
        Solve();
    
        return 0;
    }
    
    
  • 相关阅读:
    【转】嵌入式软件:C语言编码规范
    【转】如何建立编码规范?
    RAS使用拨号网络拨号的类
    UDP 通讯代码
    【转】heap与stack的区别
    关于textarea在safari chrome下可拖动大小的问题
    Java网络编程入门
    诺基亚发布了它的第一台android手机,x和x+机型
    Spring学习笔记之入门(二)
    Spring学习笔记之入门(一)
  • 原文地址:https://www.cnblogs.com/cnyali-Tea/p/11439945.html
Copyright © 2020-2023  润新知