标记传递 题解
题目链接:【数据删除】 来源:校内模拟赛。
一道还算板的DP,没有看出来,我是树根。感觉这题的强度其实是不如The Doubling Game 2的。
注意到我们可以钦定一个点为根,然后开始传递。那么操作也就可以视作两部分:向下传递,向上传递。这样子一定是最优的,并且两部分等价。(可以反着操作)。
因此可以只对一半进行计数。接下来就是比较经典的了,式子可以写做 \(f_u = (siz_u-1)! / (\prod_{v\in u} (siz_v)!) \times \prod_{v \in u} f_v\)。接下来直接大力换根,做完了。
Code
#include<bits/stdc++.h>
using namespace std;
#define LL long long
#define fi first
#define se second
#define IOS ios::sync_with_stdio(false);cin.tie(0),cout.tie(0)
#define File(s) freopen(s".in","r",stdin);freopen(s".out","w",stdout)
const LL mod = 1e9 + 7;
const int N = 2e5 + 10;
LL fac[N],inv[N];
LL qpow(LL a,LL b){
if(b == 0) return 1;
if(b == 1) return a;
LL re = qpow(a,b/2);
re *= re;
re %= mod;
if(b & 1ll) re *= a;
return re % mod;
}
int n;
vector<int> G[N];
int siz[N];
LL f[N];
void dfs(int u,int fa){
siz[u] = 1;
for(int v : G[u]){
if(v == fa) continue;
dfs(v,u);
siz[u] += siz[v];
}
return ;
}
void solve(int u,int fa){
for(int v : G[u]){
if(v == fa) continue;
solve(v,u);
}
f[u] = fac[siz[u]-1];
for(int v : G[u]){
if(v == fa) continue;
f[u] = f[u] * inv[siz[v]] % mod;
f[u] = f[u] * f[v] % mod;
}
}
LL ans = 0;
void solve2(int u,int fa){
ans += f[u] * f[u] % mod;
ans %= mod;
for(int v : G[u]){
if(v == fa) continue;
f[v] = f[u] * siz[v] % mod * qpow(n-siz[v],mod-2) % mod;
solve2(v,u);
}
return ;
}
int main()
{
IOS;
File("flag");
cin >> n;
for(int i=1;i<n;i++){
int u,v;
cin >> u >> v;
G[u].push_back(v);
G[v].push_back(u);
}
fac[0] = 1;
for(int i=1;i<=n;i++)
fac[i] = fac[i-1] * i % mod;
inv[n] = qpow(fac[n],mod-2);
for(int i=n-1;i>=0;i--)
inv[i] = inv[i+1] * (i+1) % mod;
dfs(1,0);
solve(1,0);
solve2(1,0);
cout << ans;
return 0;
}

浙公网安备 33010602011771号