TopCoder SRM 712 Div1 600 AverageVarianceSubtree
阿新 • • 發佈:2018-12-18
卡精度沒素質。。。。
今天才知道有__float128
這種東西,問了一下noip不能用。。。
傳送門 個點的樹,每個點有一個權值,任選一棵非空子樹,求其中所有點方差的期望。
裸的樹形DP,感覺不值600,不過之前做過另一道樹形DP也是600…
反正這種題吧,大概xy肯定會說要樹轉二叉樹(並不用)
我們先來尻驢一下方差是個啥
emmm之前做的方差題裡好像很多都有一句類似"可以證明是整數,然後整數比較好處理我就尻驢把它變整數。為了方便就讓,,把式子一通展開就得到了:
這個式子一看就好看多了(並沒有)
然後就開始樹形DP的常規操作…(以下“所有子樹”表示以為根,子樹大小為的子樹)
- 表示方案數
- 表示所有子樹中的和
- 表示所有子樹中的和
- 表示所有子樹中的和
轉移的話儘量自己思考吧,不難的(其實是不負責任的博主懶得寫)。實在不懂就留言吧,我儘量回答。
其實感覺這種題很多就是暴力展開式子,然後把長得像的丟一起…好像做個幾道就能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;
}