• P4827 [国家集训队] Crash 的文明世界 第二类斯特林数


    题意:

    戳这里

    分析:

    • 前置芝士:第二类斯特林数

    我们先写出答案的式子

    (displaystyle S(i)=sum_{j=1}^ndis(i,j)^k)

    我们按照是否在子树内进行分类一下,而且我们发现似乎没有办法直接统计 (k) 次方,很容易想到第二类斯特林数可以优化 (k) 次方的和

    [S(i)=sum_{d=0}^kd!S_k^dsum_jC_{dis(i,j)}^d \ =sum_{d=0}^kd!S_k^d(sum_{jin i}C_{dis(j,i)}^d+sum_{j otin i}C_{dis(i,j)}^d) ]

    然后我们记括号里第一个式子为 (dp1[i][d]) 第二个式子为 (dp2[i][d])

    子树内的答案很好统计所以我们先来推一下 (dp1)

    [dp1[i][d]=sum_{jin i} C_{dis(i,j)}^d \ =[d==0]+sum_{vand fa[v]==i} sum_{jin v} C_{dis(v,j)+1}^d \ =[d==0]+sum_{vand fa[v]==i}sum_{jin v}(C_{dis(v,j)}^d+C_{dis(v,j)}^{d-1}) \ =[d==0]+sum_{vand fa[v]==i}(dp1[v][j]+dp1[v][j-1]) ]

    接下来要统计子树外的答案

    [dp2[i][d]=sum_{j otin i}C_{dis(i,j)}^d \ =sum_{j otin fa}C_{dis(fa,j)+1}^d+sum_{jin fa} C_{dis(fa,j)+1}^d-sum_{jin i}C_{dis(i,j)+2}^d \ =(dp2[fa][d]+dp2[fa][d-1])+(dp1[fa][d]+dp1[fa][d-1])-(dp1[i][d]+2*dp[i][d-1]+dp[i][d-2]) ]

    其中 (dp2[1][d]) 恒等于 (0)

    直接换根 DP

    代码:

    #include<bits/stdc++.h>
    #define inl inline 
    #define reg register
    #define pb push_back
    using namespace std;
    
    namespace zzc
    {
        typedef long long ll;
        inl int read()
        {
            int x=0,f=1;char ch=getchar();
            while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
            while(isdigit(ch)){x=x*10+ch-48;ch=getchar();}
            return x*f;
        }
    
        const int maxn = 5e4+5;
        const int maxk = 200;
        const ll mod = 10007;
        ll s[maxk][maxk],fac[maxk],dp1[maxn][maxk],dp2[maxn][maxk];
        ll n,k;
        vector<int> e[maxn];
    
        void init()
        {
            s[0][0]=1;
            for(reg ll i=1;i<=150;i++) for(reg ll j=1;j<=i;j++) s[i][j]=(s[i-1][j-1]+s[i-1][j]*j%mod)%mod;
            fac[0]=1;
            for(reg ll i=1;i<=150;i++) fac[i]=fac[i-1]*i%mod;
        }
    
        void dfs1(int u,int ff)
        {
            dp1[u][0]=1;
            for(auto v:e[u])
            {
                if(v==ff) continue;
                dfs1(v,u);
                dp1[u][0]=(dp1[u][0]+dp1[v][0])%mod;
                for(reg int i=1;i<=k;i++) dp1[u][i]=(dp1[u][i]+dp1[v][i]+dp1[v][i-1])%mod;
            }
        }
    
        void dfs2(int u,int ff)
        {
            if(u!=1)
            {
                dp2[u][0]=(dp2[ff][0]+dp1[ff][0]-dp1[u][0]+mod)%mod;
                dp2[u][1]=(dp2[ff][1]+dp2[ff][0]+dp1[ff][1]+dp1[ff][0]-dp1[u][1]-2*dp1[u][0]+3*mod)%mod;
                for(reg int i=2;i<=k;i++) dp2[u][i]=( (dp2[ff][i]+dp2[ff][i-1])%mod + (dp1[ff][i]+dp1[ff][i-1])%mod -(dp1[u][i]+2*dp1[u][i-1]+dp1[u][i-2])%mod + mod)%mod;
            }
            for(auto v:e[u]) if(v!=ff) dfs2(v,u); 
        }
    
        void work()
        {
            int a,b;
            init();
            n=read();k=read();
            for(reg int i=1;i<n;i++)
            {
                a=read();b=read();
                e[a].pb(b);e[b].pb(a);
            }
            dfs1(1,0);dfs2(1,0);
            for(reg int i=1;i<=n;i++)
            {
                ll ans=0;
                for(reg int d=0;d<=k;d++) ans=(ans+fac[d]*s[k][d]%mod*(dp1[i][d]+dp2[i][d])%mod)%mod;
                printf("%lld
    ",ans);
            }
        }
    
    }
    
    int main()
    {
        zzc::work();
        return 0;
    }
    
  • 相关阅读:
    linux I2C 读写 tlv320dac3100
    ubuntu lfs
    安装和使用花生壳(linux)
    vim 配置
    vim
    gnome2 恢复默认 panel
    ubuntu 挂在 jffs2 文件
    gstreamer 播放
    gstreamer 环境变亮设置
    探讨【IGE】的源代码【五】。
  • 原文地址:https://www.cnblogs.com/youth518/p/14349368.html
Copyright © 2020-2023  润新知