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

题意:

戳这里

分析:

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

我们先写出答案的式子

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

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

\[S(i)=\sum_{d=0}^kd!S_k^d\sum_jC_{dis(i,j)}^d \\ =\sum_{d=0}^kd!S_k^d(\sum_{j\in i}C_{dis(j,i)}^d+\sum_{j\notin i}C_{dis(i,j)}^d) \]

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

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

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

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

\[dp2[i][d]=\sum_{j\notin i}C_{dis(i,j)}^d \\ =\sum_{j\notin fa}C_{dis(fa,j)+1}^d+\sum_{j\in fa} C_{dis(fa,j)+1}^d-\sum_{j\in 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\n",ans);
        }
    }

}

int main()
{
    zzc::work();
    return 0;
}
posted @ 2021-01-30 16:11  youth518  阅读(56)  评论(0)    收藏  举报