Day 11.25模擬賽遊記
阿新 • • 發佈:2020-11-25
又是測資料的一天?不知情的我又爆零了。
T2.樹的解構(deconstruct)
題目大意:給定\(1\)為根,隨機選擇一條邊刪去,刪去的代價為這條邊所指向的子節點的子樹大小,求刪去\(n-1\)條邊時的期望。
因為整棵子樹計算會有子孫節點是否被刪除過,所以我們可以只計算當前這個點的貢獻,而不是這棵子樹的。
對於當前節點肯定只有到根節點的路徑上的邊有貢獻,所以其餘邊的方案數為\(C_{n-1}^{dep_u}\times (n-dep_u-1)!\),然後計算貢獻就從一棵樹變成了一條鏈。
我們現在來考慮一條鏈的情況,因為我們要計算貢獻的點只是鏈的末尾,所以列舉貢獻的多少,然後計算即可,要考慮我們計算的是所有方案的貢獻,所以貢獻還要乘以當前的方案數,可證明為第二類斯特林數,遞推公式為\(f_i=f_{i-1}*i+(i-1)!\) ,先預處理好,然後\(O(n)\)計算即可。
手起碼落,把這題咔嚓了:
#include<bits/stdc++.h> #define re register #define mod 1000000007 using namespace std; inline int read() { re int x=0,f=1; re char ch=getchar(); for(;ch>'9'||ch<'0';ch=getchar()) if(ch=='-') f*=-1; for(;ch>='0'&&ch<='9';ch=getchar()) x=(x<<1)+(x<<3)+(ch^48); return x*f; } const int N=2000005; inline long long Pow(long long x,int y) { re long long sum=1; for(;y;y>>=1,x=x*x%mod) if(y&1) sum=sum*x%mod; return sum; } struct edge{int v,net;}e[N]; int n,cnt,hd[N],dep[N]; long long ans,jc[N]={1},inv[N]={1},f[N]; queue <int> q; inline void add(int u,int v){e[++cnt].v=v,e[cnt].net=hd[u],hd[u]=cnt;} void first() { q.push(1); for(re int u;!q.empty();q.pop()) { u=q.front(); for(re int i=hd[u],v;i;i=e[i].net) { v=e[i].v; dep[v]=dep[u]+1; q.push(v); } } } inline long long C(int m,int n){return jc[m]*inv[n]%mod*inv[m-n]%mod;} int main() { freopen("deconstruct.in","r",stdin); freopen("deconstruct.out","w",stdout); scanf("%d",&n); for(re int i=1;i<=n;i++) jc[i]=jc[i-1]*i%mod,inv[i]=Pow(jc[i],mod-2); for(re int i=2;i<=n;i++) add(read(),i); f[1]=1;for(re int i=1;i<=n;i++) f[i]=(f[i-1]*i+jc[i-1])%mod; first(); for(re int i=1;i<=n;i++) ans=(ans+C(n-1,dep[i])*jc[n-dep[i]-1]%mod*f[dep[i]]%mod)%mod; printf("%lld",ans*inv[n-1]%mod); return 0; }