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