1. 程式人生 > >TopCoder SRM 712 Div1 600 AverageVarianceSubtree

TopCoder SRM 712 Div1 600 AverageVarianceSubtree

卡精度沒素質。。。。 今天才知道有__float128這種東西,問了一下noip不能用。。。

DescriptionDescription

傳送門 nn個點的樹,每個點有一個權值,任選一棵非空子樹,求其中所有點方差的期望。

SolutionSolution

裸的樹形DP,感覺不值600,不過之前做過另一道樹形DP也是600… 反正這種題吧,大概xy肯定會說要樹轉二叉樹(並不用

我們先來尻驢一下方差是個啥

S=(x1xˉ)2+(x1xˉ)2++(xnxˉ)2nS=\frac{(x_1-\bar{x})^2+(x_1-\bar{x})^2+ \cdots +(x_n-\bar{x})^2}{n}

emmm之前做的方差題裡好像很多都有一句類似"可以證明S×n2S \times n^2是整數,然後整數比較好處理我就尻驢把它變整數。為了方便就讓s1=i=1nxis_1=\sum_{i=1}^n x_is2=i=1nxi2s_2=\sum_{i=1}^n x_i^2,把式子一通展開就得到了:

Sn2=ns2s12S \cdot n^2=n \cdot s_2-s_1^2

這個式子一看就好看多了(並沒有

然後就開始樹形DP的常規操作…(以下“所有子樹”表示以i

i為根,子樹大小為jj的子樹)

  • f[i][j]f[i][j] 表示方案數
  • h[i][j]h[i][j] 表示所有子樹中s1s_1的和
  • s[i][j]s[i][j] 表示所有子樹中s12s_1^2的和
  • s2[i][j]s2[i][j] 表示所有子樹中s2s_2的和

轉移的話儘量自己思考吧,不難的(其實是不負責任的博主懶得寫)。實在不懂就留言吧,我儘量回答。 其實感覺這種題很多就是暴力展開式子,然後把長得像的丟一起…好像做個幾道就能get到其中的套路…

#include <bits/stdc++.h>
#define
ll long long
#define fr(i,x,y) for(int i=x;i<=y;i++) #define rf(i,x,y) for(int i=x;i>=y;i--) //#define double long double using namespace std; const int N=55; const int M=N<<1; int n,w[N]; int cnt,head[N],Next[M],v[M]; __float128 f[N][N],s[N][N],s2[N][N],h[N][N]; template<class T> void checkmin(T &a,const T &b) { if (b<a) a=b; } template<class T> void checkmax(T &a,const T &b) { if (b>a) a=b; } class AverageVarianceSubtree { public: double average( vector <int> p, vector <int> weight ) ; }; void add(int x,int y){ Next[++cnt]=head[x]; head[x]=cnt; v[cnt]=y; } ll sqr(ll x){ return x*x; } void dfs(int x,int fa){ f[x][1]=1; s[x][1]=sqr(w[x]); s2[x][1]=sqr(w[x]); h[x][1]=w[x]; for(int i=head[x];i;i=Next[i]){ dfs(v[i],x); //f[x]+=f[x]*f[v[i]]; rf(j,n,1) rf(k,n,1) if (j+k<=n){ f[x][j+k]+=f[x][j]*f[v[i]][k]; s[x][j+k]+=f[v[i]][k]*s[x][j]+f[x][j]*s[v[i]][k]+2*h[x][j]*h[v[i]][k]; s2[x][j+k]+=s2[x][j]*f[v[i]][k]+s2[v[i]][k]*f[x][j]; h[x][j+k]+=h[x][j]*f[v[i]][k]+h[v[i]][k]*f[x][j]; } } } double AverageVarianceSubtree::average(vector <int> p, vector <int> weight) { n=weight.size(); fr(i,2,n) add(p[i-2]+1,i); fr(i,1,n) w[i]=weight[i-1]; dfs(1,0); __float128 sum=0,z=0; fr(i,1,n){ __float128 ss=0,ss2=0; fr(j,1,n){ ss+=s[j][i]; ss2+=s2[j][i]; sum+=(s2[j][i]*i-s[j][i])/(i*i); z+=f[j][i]; } } double ans=sum/z; return ans; }