[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;
}
给时光以生命,而不是给生命以时光。

浙公网安备 33010602011771号