前言
另一道斯特林数相关的题目,然而可能更考树形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=1∑ndis(i,j)k
数据范围
n ≤ 50000 , k ≤ 150 n\le50000,k\le 150 n≤50000,k≤150
题解
直接上正解吧
同理这里有幂次
回到式子
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=0∑n{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=1∑ndis(i,j)k=j=1∑nl=0∑k{kl}dis(i,j)l↓=l=0∑k{kl}j=1∑ndis(i,j)l↓=l=0∑k{kl}l!j=1∑n(ldis(i,j))
我们发现求斯特林数是可以
Θ
(
k
2
)
\Theta(k^2)
Θ(k2)做的,求阶乘也很方便,是
Θ
(
k
)
\Theta(k)
Θ(k)的,现在关键是要求每个点,对于每个
1
≤
l
≤
k
1\le l\le k
1≤l≤k的
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=1∑n(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(n−1,m−1)+C(n−1,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题
算是一种思路的联系吧