根据期望的线性性(orz xuruifan,我们一定要叫线性性,不能叫可加性),期望幸运点对数等于每个幸运点对被选中的概率之和
由于每个点都是等价的,所以每个点对也是等价的,所以我们只需要计算1个点对被选中的概率,乘以点对数再乘以2(因为是有序的)即可
一个点对被选中的概率等于他在每次操作下被选中的概率之和
假设这个点对是(x,y)
对于一个人,第i次操作一定会选择一个点,x被选中的概率是1/n
如果这次选择了x,在之前的i-1次操作中,一定不会选择x,所以每次会在n-1个点中随机选一个没被选中的,所以y被选中的概率是i-1/n-1
所以一个人的第i次操作对答案的贡献是(1/n)*(i-1/n-1)*幸运点对数×2
至于如何求幸运点对数,这是点分治的经典问题,可以在O(mn log n)时间内求出
其实我们也可以用类似BZOJ4543 POI2014 HOTEL加强版的方法来优化n^2的DP,在O(nm)的时间,O(n)的空间内求出
我写的是优化DP,因为我做这道题的时候脑抽,忘了这是点分治经典问题了-_-
#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<ctime>
#include<algorithm>
#include<iomanip>
#include<vector>
#include<stack>
#include<queue>
#include<map>
#include<set>
#include<bitset>
using namespace std;
#define MAXN 50010
#define MAXM 1010
#define ll long long
#define INF 1000000000
#define MOD 1000000007
#define eps 1e-8
struct vec{
int to;
int fro;
};
vec mp[MAXN*2];
int tai[MAXN],cnt;
int g[MAXN];
int F[MAXN*8];
int *f[MAXN];
int *hat=F+2;
int d[MAXN];
int n,m;
int l[MAXN];
int son[MAXN];
double cs[5],ans[5];
int lw[MAXN];
int dep[MAXN];
inline void be(int x,int y){
mp[++cnt].to=y;
mp[cnt].fro=tai[x];
tai[x]=cnt;
}
inline void bde(int x,int y){
be(x,y);
be(y,x);
}
void pre(int x,int F){
int i,y;
lw[x]=x;
dep[x]=dep[F]+1;
for(i=tai[x];i;i=mp[i].fro){
y=mp[i].to;
if(y==F){
continue ;
}
pre(y,x);
if(d[y]+1>d[x]){
son[x]=y;
lw[x]=lw[y];
d[x]=d[y]+1;
}
}
for(i=tai[x];i;i=mp[i].fro){
y=mp[i].to;
if(y!=son[x]&&y!=F){
hat+=dep[lw[y]]-dep[y]+2;
f[lw[y]]=hat;
hat+=5;
}
}
if(x==1){
hat+=dep[lw[x]]-dep[x]+2;
f[lw[x]]=hat;
}
}
void dfs(int x,int F){
int i,j,k,y;
for(i=tai[x];i;i=mp[i].fro){
y=mp[i].to;
if(y==F){
continue ;
}
dfs(y,x);
if(y==son[x]){
f[x]=f[y]-1;
g[x]+=g[y];
for(j=1;j<=m;j++){
if(l[j]-1<=d[y]){
g[x]+=f[y][l[j]-1];
}
}
}
}
f[x][0]=1;
for(i=tai[x];i;i=mp[i].fro){
y=mp[i].to;
if(y==F||y==son[x]){
continue ;
}
g[x]+=g[y];
for(j=0;j<=d[y];j++){
for(k=1;k<=m;k++){
if(j<l[k]&&l[k]-j-1<=d[x]){
g[x]+=f[y][j]*f[x][l[k]-j-1];
}
}
}
for(j=0;j<=d[y];j++){
f[x][j+1]+=f[y][j];
}
}
}
int main(){
int i,x,y;
scanf("%d%d",&n,&m);
for(i=1;i<=m;i++){
scanf("%d",&l[i]);
}
for(i=1;i<n;i++){
scanf("%d%d",&x,&y);
bde(x,y);
}
pre(1,0);
dfs(1,0);
for(i=1;i<=n;i++){
ans[(i-1)%3+1]+=1.0/n*cs[(i-1)%3+1]*g[1]*2;
cs[(i-1)%3+1]+=1.0/(n-1);
}
for(i=1;i<=3;i++){
printf("%.2lf\n",ans[i]);
}
return 0;
}
/*
6 2
1 3
1 2
2 3
1 4
1 5
2 6
*/