反正是部分方法借鉴别人的就懒得称之为原创了
不难得出最少次数的传输方法是选择一个点作为根,其他所有点将消息从下往上传至该点再往下分发。
分为两部分:正反向的树形dp和逆元
s[i]:以节点i为根所能收到消息的方法数
ss[i]: s[j]相乘的积,j为i的子节点
c[i]:树i的总节点数
cc[i]: (c[j])!相乘的积,j为i的子节点
s[i] = (c[i]-1)! * ss[i] / cc[i];
由于涉及到除法取模,要用到逆元来保证精确度,举个简单的例子:8/4 == 2; 设a是4相对于2^31的逆元,则 8/4 % (2^31) == 8 * a % (2^31)
a = b^(p-2)%p
通过一遍深搜得到以每个节点i为根时节点的s,按原顺序遍历,计算并修改s为以i为全图的根时所能得到的方法数
s[i] = (n-1)!*ss[i]/cc[i]/(n - c[i])! * s[pre]*(n-1-c[i])!*c[i]!/(n-1)!/s[i]
= ss[i]*s[pre]*c[i]! / ((n-c[i])*cc[i]*s[i])
总数 = s[i]*s[i] (i:1~n)
#pragma comment(linker, "/STACK:102400000,102400000") #include <cstdio> #include <algorithm> #include <vector> using namespace std; typedef __int64 ll; const int MAXN = 1000005; const ll mod = 1000000007; ll a[MAXN]/*A!*/, c[MAXN], cc[MAXN], s[MAXN], ss[MAXN], sum; int n; struct edge { int v, next; }ee[MAXN<<1]; int head[MAXN], cnt; void add(int u, int v) { ee[cnt].v = v; ee[cnt].next = head[u]; head[u] = cnt++; } ll mPower(ll a) { ll res = 1, p = a, t = mod-2; while (t) { if (t & 1) res = res * p %mod; p=p*p%mod; t >>= 1; } return res; } void dfs(int u, int pre) { c[u] = 1; cc[u] = 1; ss[u] = 1; for (int i = head[u]; ~i; i = ee[i].next) { int v = ee[i].v; if (v != pre) { dfs(v, u); c[u] += c[v]; } } for (int i = head[u]; ~i; i = ee[i].next) { int v = ee[i].v; if (v != pre) { cc[u] = cc[u]*a[c[v]]%mod; ss[u] = ss[u]*s[v]%mod; } } s[u] = a[c[u]-1]*ss[u]%mod*mPower(cc[u])%mod; } void solve(int u, int pre) { ll tp = (n-c[u])*cc[u]%mod*s[u]%mod; s[u] = ss[u]*s[pre]%mod*a[c[u]]%mod*mPower(tp)%mod; sum = (sum + s[u]*s[u]%mod)%mod; for (int i = head[u]; ~i; i = ee[i].next) { int v = ee[i].v; if (v != pre) { solve(v, u); } } } int main() { #ifndef ONLINE_JUDGE freopen("in.txt", "r", stdin); #endif a[0] = 1; for (int i = 1; i<= MAXN-5; ++i) a[i] = a[i-1]*i%mod; int t; scanf("%d", &t); while (t--) { int u, v; memset(head, -1, sizeof head); cnt = 0; scanf("%d", &n); for (int i = 0; i< n-1; ++i) { scanf("%d%d", &u, &v); add(u, v); add(v, u); } dfs(1, -1); sum = s[1]*s[1]%mod; for (int i = head[1]; ~i; i=ee[i].next) { solve(ee[i].v, 1); } printf("%I64d\n", sum); } return 0; }
hdu 4661 Message Passing(树形dp)
最新推荐文章于 2019-04-09 19:23:00 发布