[by myy][2016-4-26]

期望问题。

有一棵树,每个节点有黑白两色,每次随机一个点,人走过去并把选择的这个点反色。直到这棵树同色为止。

问期望的路径长度(在模意义下进行)

 

一个点的期望贡献是其他点到这个点的距离和 / n

可以发现所有的黑点期望选择的次数相同,所有的白点期望选择的次数相同。(互为等价。)

设val[i][0/1]代表这个树上有i个黑点,当前点的颜色是白/黑

列式子。

设未知量(其实有四个未知量然而有两个是0)

最后有两个二元一次方程。

解出来次数分配给所有黑白点即可。

 

注意解方程的坑。

比如A/B的系数为0之类的东西。

或者你列的并不是ax + by = c,而是ax + by + c = 0。。

#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#define maxn 100010
using namespace std;
typedef long long ll;
const int md = 1e9 + 7;
ll power_mod(ll a, ll b = md - 2){
	ll ret = 1;
	while(b > 0){
		if(b & 1)ret = ret * a % md;
		a = a * a % md;
		b >>= 1;
	}return ret;
}

ll dis[maxn];
int size[maxn];
int n;
char str[maxn];
struct Edge{int to, nxt;}edge[maxn << 1];
int h[maxn], cnt;
void add(int u, int v){
	cnt ++;
	edge[cnt].to = v;
	edge[cnt].nxt = h[u];
	h[u] = cnt;
}

void dfs(int u){
	size[u] = 1;
	for(int i = h[u]; i; i = edge[i].nxt){
		int v = edge[i].to;
		dfs(v);
		size[u] += size[v];
		dis[u] += dis[v] + size[v];
	}
}

void dfs2(int u, ll d){
	ll Sum = dis[u];
	dis[u] += d;
	for(int i = h[u]; i; i = edge[i].nxt){
		int v = edge[i].to;
		dfs2(v, d + Sum - (dis[v] + size[v]) + (n - size[v]));
	}
}

//----------------------------------------------------------------//
struct opt{
	ll a, b, c;
	opt(ll a = 0, ll b = 0, ll c = 0):a(a), b(b), c(c){}
}val[maxn][2], final[2];

opt operator+(const opt& x, const opt& y){return opt((x.a + y.a) % md, (x.b + y.b) % md, (x.c + y.c) % md);}
opt operator-(const opt& x, const opt& y){return opt((x.a - y.a) % md, (x.b - y.b) % md, (x.c - y.c) % md);}
opt operator*(const opt& x, const ll& y){return opt(x.a * y % md, x.b * y % md, x.c * y % md);}
//----------------------------------------------------------------//

ll inv[maxn], K[maxn];
int main(){
	freopen("C.in", "r", stdin);
	freopen("C.out", "w", stdout);
	scanf("%d%s", &n, str + 1);
	int u;
	for(int i = 2; i <= n; i ++){
		scanf("%d", &u);
		add(u, i);
	}
	
	dfs(1);
	dfs2(1, 0);
	
	int To = 0; inv[0] = 1;
	for(int i = 1; i <= n; i ++){
		To += (str[i] == '1');
		inv[i] = power_mod(i);
	}

	val[1][0] = opt(1, 0, 0);
	val[1][1] = opt(0, 1, 0);
	for(int i = 1; i < n; i ++){
		val[i+1][1] = (val[i][1] * n - val[i-1][0] - val[i-1][1] * (i-1) - opt(0, 0, 1)) * inv[n-i];
		val[i+1][0] = (val[i][0] * n - val[i-1][0] * i - val[i+1][1] - opt(0, 0, 1)) * inv[n-i-1];
	}
//--------------------------------------------------------------------------------------------------------//
	final[0] = val[n][0];
	final[1] = val[n][1];
	
	(final[0].b += md) %= md;
	(final[1].b += md) %= md;
	
	if(final[0].b)final[0] = final[0] * power_mod(final[0].b);
	if(final[1].b)final[1] = final[1] * power_mod(final[1].b);
	final[0].c = -final[0].c;
	final[1].c = -final[1].c;
	opt nw;
	if(final[0].b == 0)nw = final[0];
	else if(final[1].b == 0)nw = final[1];
	else nw = final[0] - final[1];
	
	nw.a = (nw.a + md) % md;
	nw = nw * power_mod(nw.a);
//--------------------------------------------------------------------------------------------------------//
	ll A = (nw.c + md) % md, B;
	if(final[0].b)B = (final[0].c - final[0].a * A % md) % md;
	else B = (final[1].c - final[1].a * A % md) % md;
	B = (B + md) % md;
	ll P = val[To][0].a * A % md + val[To][0].b * B % md + val[To][0].c; P %= md;
	ll Q = val[To][1].a * A % md + val[To][1].b * B % md + val[To][1].c; Q %= md;
//--------------------------------------------------------------------------------------------------------//
	ll ans = 0;
	for(int i = 1; i <= n; i ++)
	    if(str[i] == '0')ans = (ans + P * dis[i] % md) % md;
	    else ans = (ans + Q * dis[i] % md) % md;
	ans = (ans + md) % md;
	ans = ans * power_mod(n) % md;
	printf("%lld\n", ans);
    return 0;
}

  

posted @ 2016-04-26 21:29  _Horizon  阅读(118)  评论(0)    收藏  举报