【Topcoder SRM697 Hard】【JZOJ5180】ConnectedStates 题解

题目大意

这里写图片描述

   n &lt; = 2000 ,   w i &lt; = 1 e 9 n&lt;=2000,~w_i&lt;=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=n2a1!a2!...an!(n2)!i=1n(ai+1)wiai+1

  其中与 a a a 无关的是 ( n − 2 ) ! × ∏ w i (n-2)!×\prod w_i (n2)!×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=n2a1!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=n2p1,p2,...,pka1!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,...,pkwp1×wp2×...×wpka1+a2+...+an=n2ka1!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} &amp;&amp;[x^{n-2-k}]\prod_{i=1}^n (\sum_{j\ge0} \frac{w_i^jx^j}{j!})\\ &amp;=&amp;[x^{n-2-k}]\prod_{i=1}^n e^{w_ix}\\ &amp;=&amp;[x^{n-2-k}]~e^{\sum w_ix}\\ &amp;=&amp;[x^{n-2-k}]\sum_{j\ge0} \frac{(\sum w_i)^j x^j}{j!}\\ &amp;=&amp;\frac{(\sum w_i)^{n-2-k}}{(n-2-k)!} \end{array} ====[xn2k]i=1n(j0j!wijxj)[xn2k]i=1newix[xn2k] ewix[xn2k]j0j!(wi)jxj(n2k)!(wi)n2k
  于是就。。做完了。

代码

#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);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值