• BZOJ 2159: Crash 的文明世界


    记得去年暑假集训的时候本来想了一个动态点分的做法的,然后写道一半因为某些不知名原因就没写了,然后就一直放着,然后发现斯特林反演真NM好写

    首先考虑用关于幂的斯特林反演:

    [m^n=sum_{i=0}^m left{ ^n_i ight} imes i! imes C_m^i ]

    套上去就是:

    [ans(x)=sum_{i=1}^n dis(i,x)^k ]

    [=sum_{i=1}^n sum_{j=0}^k left{ ^k_j ight} imes C_{dis(i,x)}^j imes j! ]

    [=sum_{j=0}^k left{ ^k_j ight} imes j! imes sum_{i=1}^n C_{dis(i,x)}^j ]

    显然我们现在只要知道(sum_{i=1}^n C_{dis(i,x)}^j)怎么求即可,设:

    [dn_{x,i}=sum_{yin x} C_{dis(x,y)}^i ]

    [up_{x,i}=sum_{y ot in x} C_{dis(x,y)}^i ]

    其中(yin x)表示(y)(x)子树内

    显然我们可以推出关于(dn)的方程:

    [dn_{x,i}=sum_{yin x} C_{dis(x,y)}^i ]

    [=[i=0]+sum_{vin son(x)}sum_{yin v} C_{dis(v,y)+1}^i ]

    [=[i=0]+sum_{vin son(x)}sum_{yin v} C_{dis(v,y)}^i+C_{dis(v,y)}^{i-1} ]

    [=[i=0]+sum_{vin son(x)} dn_{v,i}+dn_{v,i-1} ]

    那么接下来就是(up)的,如果熟悉换根DP那一套的话会很容易推出来,注意要容斥掉一部分:

    [up_{x,i}=sum_{y ot in x} C_{dis(x,y)}^i ]

    [=sum_{y ot in fa(x)} C_{dis(fa(x),y)+1}^i+sum_{yin fa(x)} C_{dis(fa(x),y)+1}^i-sum_{yin x} C_{dis(x,y)+2}^i ]

    [=up_{fa(x),i}+up_{fa(x),i-1}+dn_{fa(x),i}+dn_{fa(x),i-1}-dn_{x,i}-2 imes dn_{x,i-1}-dn_{x,i-2} ]

    边界就是(up_{1,i}=0)

    然后就做完了,复杂度(O(nk))

    PS:BZOJ上又要改输入又会莫名挂掉,因此下面的代码是Luogu上的同题

    #include<cstdio>
    #define RI register int
    #define CI const int&
    using namespace std;
    const int N=500005,M=155,mod=10007;
    struct edge
    {
    	int to,nxt;
    }e[N<<1]; int n,head[N],cnt,k,x,y,fact[N],S[M][M],up[N][M],dn[N][M],ans;
    inline void addedge(CI x,CI y)
    {
    	e[++cnt]=(edge){y,head[x]}; head[x]=cnt;
    	e[++cnt]=(edge){x,head[y]}; head[y]=cnt;
    }
    inline int fix(int x)
    {
    	while (x<0) x+=mod; while (x>=mod) x-=mod; return x;
    }
    inline void init(CI n)
    {
    	RI i,j; for (fact[0]=i=1;i<=n;++i) fact[i]=1LL*fact[i-1]*i%mod;
    	for (S[0][0]=i=1;i<=n;++i) for (j=0;j<=i;++j)
    	S[i][j]=fix((j?S[i-1][j-1]:0)+1LL*j*S[i-1][j]%mod);
    }
    #define to e[i].to
    inline void DFS1(CI now=1,CI fa=0)
    {
    	dn[now][0]=1; for (RI i=head[now],j;i;i=e[i].nxt) if (to!=fa)
    	for (DFS1(to,now),j=0;j<=k;++j) dn[now][j]=fix(dn[now][j]+(j?dn[to][j-1]:0)+dn[to][j]);
    }
    inline void DFS2(CI now=1,CI fa=0)
    {
    	RI i; if (now!=1)
    	{
    		for (i=0;i<=k;++i)
    		up[now][i]=fix(up[fa][i]+(i?up[fa][i-1]:0)+dn[fa][i]+(i?dn[fa][i-1]:0)-dn[now][i]-2*(i?dn[now][i-1]:0)-(i>=2?dn[now][i-2]:0));
    	}
    	for (i=head[now];i;i=e[i].nxt) if (to!=fa) DFS2(to,now);
    }
    #undef to
    int main()
    {
    	RI i,j; for (scanf("%d%d",&n,&k),i=1;i<n;++i) scanf("%d%d",&x,&y),addedge(x,y);
    	for (init(k),DFS1(),DFS2(),i=1;i<=n;++i)
    	{
    		for (ans=0,j=0;j<=k;++j)
    		ans=fix(ans+1LL*fact[j]*S[k][j]%mod*(up[i][j]+dn[i][j])%mod); printf("%d
    ",ans);
    	}
    	return 0;
    }
    
  • 相关阅读:
    剑指Offer-Python(6-10)
    Python对MySQL进行增删查改
    剑指Offer-Python(1-5)
    转载:Python中collections模块
    读取单词文件并查某个单词出现的次数
    Python正则表达式-换行的匹配
    Python爬虫-换行的匹配
    转载:Pycharm的常用快捷键
    Python 正则表达式
    Python的类与对象
  • 原文地址:https://www.cnblogs.com/cjjsb/p/12240707.html
Copyright © 2020-2023  润新知