题目大意
n < = 2000 , w i < = 1 e 9 n<=2000,~w_i<=1e9 n<=2000, wi<=1e9
\\
\\
\\
题解
稍微有点妙啊。。。
与度数有关的无根树计数,考虑 prufer 序。
暴力可以直接
O
(
n
3
)
O(n^3)
O(n3) dp 计算答案。
考虑优化。
假设第 i i i 个数在 prufer 序的出现次数是 a i a_i ai,那么你求的是: ∑ a 1 + a 2 + . . . + a n = n − 2 ( n − 2 ) ! a 1 ! a 2 ! . . . a n ! ∏ i = 1 n ( a i + 1 ) w i a i + 1 \sum_{a_1+a_2+...+a_n=n-2} \frac{(n-2)!}{a_1!a_2!...a_n!} \prod_{i=1}^n (a_i+1)w_i^{a_i+1} a1+a2+...+an=n−2∑a1!a2!...an!(n−2)!i=1∏n(ai+1)wiai+1
其中与
a
a
a 无关的是
(
n
−
2
)
!
×
∏
w
i
(n-2)!×\prod w_i
(n−2)!×∏wi,去掉之后原式变成:
∑
a
1
+
a
2
+
.
.
.
+
a
n
=
n
−
2
∏
i
=
1
n
(
a
i
+
1
)
w
i
a
i
a
1
!
a
2
!
.
.
.
a
n
!
\sum_{a_1+a_2+...+a_n=n-2} \frac{\prod_{i=1}^n (a_i+1)w_i^{a_i}}{a_1!a_2!...a_n!}
a1+a2+...+an=n−2∑a1!a2!...an!∏i=1n(ai+1)wiai
接着考虑拆开
∏
(
a
i
+
1
)
\prod (a_i+1)
∏(ai+1),拆开后的每一项就相当于我选择一些
a
i
a_i
ai 乘起来。假设我选择的是
a
p
1
,
a
p
2
,
.
.
.
,
a
p
k
a_{p_1},a_{p_2},...,a_{p_k}
ap1,ap2,...,apk,则有:
∑
a
1
+
a
2
+
.
.
.
+
a
n
=
n
−
2
∑
p
1
,
p
2
,
.
.
.
,
p
k
a
p
1
×
a
p
2
×
.
.
.
×
a
p
k
×
∏
i
=
1
n
w
i
a
i
a
1
!
a
2
!
.
.
.
a
n
!
\sum_{a_1+a_2+...+a_n=n-2} \sum_{p_1,p_2,...,p_k} \frac{a_{p_1}×a_{p_2}×...×a_{p_k}×\prod_{i=1}^n w_i^{a_i}}{a_1!a_2!...a_n!}
a1+a2+...+an=n−2∑p1,p2,...,pk∑a1!a2!...an!ap1×ap2×...×apk×∏i=1nwiai
上面的
a
a
a 会跟下面的阶乘约掉,那么我可以一开始就给这一部分
a
a
a 减
1
1
1,然后乘上后面少了的
w
w
w,相当于:
∑
p
1
,
p
2
,
.
.
.
,
p
k
w
p
1
×
w
p
2
×
.
.
.
×
w
p
k
∑
a
1
+
a
2
+
.
.
.
+
a
n
=
n
−
2
−
k
∏
i
=
1
n
w
i
a
i
a
1
!
a
2
!
.
.
.
a
n
!
\sum_{p_1,p_2,...,p_k} w_{p_1}×w_{p_2}×...×w_{p_k}\sum_{a_1+a_2+...+a_n=n-2-k} \frac{\prod_{i=1}^n w_i^{a_i}}{a_1!a_2!...a_n!}
p1,p2,...,pk∑wp1×wp2×...×wpka1+a2+...+an=n−2−k∑a1!a2!...an!∏i=1nwiai
注意到我只要枚举
k
k
k 的话,前后两部分就独立了。前面是个背包,所以现在化简后面。
后面这个东西跟 EGF(指数型生成函数) 很像,相当于求 :
[
x
n
−
2
−
k
]
∏
i
=
1
n
(
∑
j
≥
0
w
i
j
x
j
j
!
)
=
[
x
n
−
2
−
k
]
∏
i
=
1
n
e
w
i
x
=
[
x
n
−
2
−
k
]
e
∑
w
i
x
=
[
x
n
−
2
−
k
]
∑
j
≥
0
(
∑
w
i
)
j
x
j
j
!
=
(
∑
w
i
)
n
−
2
−
k
(
n
−
2
−
k
)
!
\begin{array}{rcl} &&[x^{n-2-k}]\prod_{i=1}^n (\sum_{j\ge0} \frac{w_i^jx^j}{j!})\\ &=&[x^{n-2-k}]\prod_{i=1}^n e^{w_ix}\\ &=&[x^{n-2-k}]~e^{\sum w_ix}\\ &=&[x^{n-2-k}]\sum_{j\ge0} \frac{(\sum w_i)^j x^j}{j!}\\ &=&\frac{(\sum w_i)^{n-2-k}}{(n-2-k)!} \end{array}
====[xn−2−k]∏i=1n(∑j≥0j!wijxj)[xn−2−k]∏i=1newix[xn−2−k] e∑wix[xn−2−k]∑j≥0j!(∑wi)jxj(n−2−k)!(∑wi)n−2−k
于是就。。做完了。
代码
#include<cstdio>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define fd(i,a,b) for(int i=a;i>=b;i--)
using namespace std;
typedef long long LL;
const int maxn=2005;
const LL mo=1e9+7;
int n,w[maxn];
LL sumw,prow=1;
LL fac[maxn],ny[maxn],f[maxn][maxn];
LL mi(LL x,LL y)
{
LL re=1;
for(; y; y>>=1, x=x*x%mo) if (y&1) re=re*x%mo;
return re;
}
void Pre()
{
fac[0]=ny[0]=1;
fo(i,1,n) fac[i]=fac[i-1]*i%mo;
ny[n]=mi(fac[n],mo-2);
fd(i,n-1,1) ny[i]=ny[i+1]*(i+1)%mo;
f[0][0]=1;
fo(i,1,n)
fo(j,0,i)
{
f[i][j]=f[i-1][j];
if (j) (f[i][j]+=f[i-1][j-1]*w[i])%=mo;
}
}
int main()
{
scanf("%d",&n);
fo(i,1,n)
{
scanf("%d",&w[i]);
if (!w[i]) {printf("0\n"); return 0;}
(sumw+=w[i])%=mo;
(prow*=w[i])%=mo;
}
Pre();
LL ans=0;
fo(k,0,n-2) (ans+=f[n][k]*mi(sumw,n-2-k)%mo*ny[n-2-k])%=mo;
printf("%lld\n",ans*prow%mo*fac[n-2]%mo);
}