[bzoj2159]Crash 的文明世界

11 篇文章 0 订阅
4 篇文章 0 订阅

前言

另一道斯特林数相关的题目,然而可能更考树形dp一些吧

题意简介

题面链接

题目大意

求对于每个点 i i i S ( i ) = ∑ j = 1 n d i s ( i , j ) k S(i)=\sum_{j=1}^ndis(i,j)^k S(i)=j=1ndis(i,j)k

数据范围

n ≤ 50000 , k ≤ 150 n\le50000,k\le 150 n50000,k150

题解

直接上正解吧

同理这里有幂次
回到式子 x n = ∑ i = 0 n { n i } x i ↓ x^n=\sum_{i=0}^n\begin{Bmatrix}n\\i\end{Bmatrix}x^{i\downarrow} xn=i=0n{ni}xi证明
直接暴力带入
S ( i ) = ∑ j = 1 n d i s ( i , j ) k = ∑ j = 1 n ∑ l = 0 k { k l } d i s ( i , j ) l ↓ = ∑ l = 0 k { k l } ∑ j = 1 n d i s ( i , j ) l ↓ = ∑ l = 0 k { k l } l ! ∑ j = 1 n ( d i s ( i , j ) l ) \begin{aligned} S(i)&=\sum_{j=1}^ndis(i,j)^k\\ &=\sum_{j=1}^n\sum_{l=0}^k\begin{Bmatrix}k\\l\end{Bmatrix}dis(i,j)^{l\downarrow}\\ &=\sum_{l=0}^k\begin{Bmatrix}k\\l\end{Bmatrix}\sum_{j=1}^ndis(i,j)^{l\downarrow}\\ &=\sum_{l=0}^k\begin{Bmatrix}k\\l\end{Bmatrix}l!\sum_{j=1}^n\binom{dis(i,j)}l\\ \end{aligned} S(i)=j=1ndis(i,j)k=j=1nl=0k{kl}dis(i,j)l=l=0k{kl}j=1ndis(i,j)l=l=0k{kl}l!j=1n(ldis(i,j))
我们发现求斯特林数是可以 Θ ( k 2 ) \Theta(k^2) Θ(k2)做的,求阶乘也很方便,是 Θ ( k ) \Theta(k) Θ(k)的,现在关键是要求每个点,对于每个 1 ≤ l ≤ k 1\le l\le k 1lk f ( i ) = ∑ j = 1 n ( d i s ( i , j ) l ) f(i)=\sum_{j=1}^n\binom{dis(i,j)}l f(i)=j=1n(ldis(i,j))
众所周知(就我不知),组合数有个很好的性质
C ( n , m ) = C ( n − 1 , m − 1 ) + C ( n − 1 , m ) C(n,m)=C(n-1,m-1)+C(n-1,m) C(n,m)=C(n1,m1)+C(n1,m)
所以直接树形dp(更准确的来说这里是上下dp)就好了
复杂度 Θ ( n k ) \Theta(nk) Θ(nk)

代码

注意:lydsy上的数据是有压缩的,洛谷是未压缩的,博主比较偷懒,所以代码是未压缩的输入

#include<cstdio>
#include<cctype>
#include<algorithm>
namespace fast_IO
{
    const int IN_LEN=10000000,OUT_LEN=10000000;
    char ibuf[IN_LEN],obuf[OUT_LEN],*ih=ibuf+IN_LEN,*oh=obuf,*lastin=ibuf+IN_LEN,*lastout=obuf+OUT_LEN-1;
    inline char getchar_(){return (ih==lastin)&&(lastin=(ih=ibuf)+fread(ibuf,1,IN_LEN,stdin),ih==lastin)?EOF:*ih++;}
    inline void putchar_(const char x){if(oh==lastout)fwrite(obuf,1,oh-obuf,stdout),oh=obuf;*oh++=x;}
    inline void flush(){fwrite(obuf,1,oh-obuf,stdout);}
}
using namespace fast_IO;
#define getchar() getchar_()
#define putchar(x) putchar_((x))
#define rg register
typedef long long LL;
template <typename T> inline T max(const T a,const T b){return a>b?a:b;}
template <typename T> inline T min(const T a,const T b){return a<b?a:b;}
template <typename T> inline void mind(T&a,const T b){a=a<b?a:b;}
template <typename T> inline void maxd(T&a,const T b){a=a>b?a:b;}
template <typename T> inline T abs(const T a){return a>0?a:-a;}
template <typename T> inline void swap(T&a,T&b){T c=a;a=b;b=c;}
template <typename T> inline T gcd(const T a,const T b){if(!b)return a;return gcd(b,a%b);}
template <typename T> inline T lcm(const T a,const T b){return a/gcd(a,b)*b;}
template <typename T> inline T square(const T x){return x*x;};
template <typename T> inline void read(T&x)
{
    char cu=getchar();x=0;bool fla=0;
    while(!isdigit(cu)){if(cu=='-')fla=1;cu=getchar();}
    while(isdigit(cu))x=x*10+cu-'0',cu=getchar();
    if(fla)x=-x;
}
template <typename T> inline void printe(const T x)
{
    if(x>=10)printe(x/10);
    putchar(x%10+'0');
}
template <typename T> inline void print(const T x)
{
    if(x<0)putchar('-'),printe(-x);
    else printe(x);
}
const int mod=10007;
const int maxn=50001,maxm=100001;
int n,k;
int S[151][151],fac[151];
int head[maxn],nxt[maxm],tow[maxm],tmp;
inline void addb(const int u,const int v)
{
	tmp++;
	nxt[tmp]=head[u];
	head[u]=tmp;
	tow[tmp]=v;
}
int f[maxn][151];
void dfs1(const int u,const int fa)
{
	f[u][0]=1;
	for(rg int i=head[u];i;i=nxt[i])
	{
		const int v=tow[i];
		if(v!=fa)
		{
			dfs1(v,u);
			f[u][0]=(f[u][0]+f[v][0])%mod;
			for(rg int j=1;j<=k;j++)f[u][j]=(f[u][j]+f[v][j]+f[v][j-1])%mod;
		}
	}
}
int z[151];
void dfs2(const int u,const int fa)
{
	for(rg int i=head[u];i;i=nxt[i])
	{
		const int v=tow[i];
		if(v!=fa)
		{
			z[0]=(f[u][0]+mod-f[v][0])%mod;
			for(rg int j=1;j<=k;j++)z[j]=(f[u][j]+mod+mod-f[v][j]-f[v][j-1])%mod;
			f[v][0]=(f[v][0]+z[0])%mod;
			for(rg int j=1;j<=k;j++)f[v][j]=(f[v][j]+z[j]+z[j-1])%mod;
			dfs2(v,u);
		}
	}
}
int main()
{
	read(n),read(k);
	S[0][0]=1;
	for(rg int i=1;i<=k;i++)
		for(rg int j=1;j<=k;j++)
			S[i][j]=(S[i-1][j-1]+j*S[i-1][j])%mod;
	fac[0]=1;
	for(rg int i=1;i<=k;i++)fac[i]=fac[i-1]*i%mod;
	for(rg int i=1;i<n;i++)
	{
		int u,v;read(u),read(v);
		addb(u,v),addb(v,u);
	}
	dfs1(1,1);
	dfs2(1,1);
	for(rg int i=1;i<=n;i++)
	{
		int ans=0;
		for(rg int j=0;j<=k;j++)ans=(ans+S[k][j]*fac[j]%mod*f[i][j])%mod;//print(f[i][j]);
		print(ans),putchar('\n');
	}
	return flush(),0;
}

总结

还是蛮清新的一道推式子+树形dp题
算是一种思路的联系吧

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值