P11032 Develop a Tree

· · 题解

题解 P11032 Develop a Tree

第一次在模拟赛解决绿题,以此纪念。

二分图,看似很高级,实则就是将图中所有点分成两部分,并且每部分之间没有连边,而题目一开始给的是一棵树,因此我们只需要用 dfs 对树进行染色,并且途中维护一个 dp 数组,即可快速求解。

需注意,本题目由于需要求模,所以需要快速幂求解乘法逆元,不会的请跳转P3811 【模板】模意义下的乘法逆元。

(细节见代码)
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 5e5 + 10;
int qpow(int a, int b, int p);
void dfs(int u, int fa);
struct node {
    int w, b; //white black
} dp[N]; //dp[i].b: 以i节点为根节点的子树中黑点的个数(w同理) 
int n, m, ans, tmp, k, p, f[N]; //f[i] : i节点的父节点
vector <int> g[N];
bool flag[N];
signed main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr); cout.tie(nullptr);
    cin >> n >> k;
    int u, v;
    for(int i=1;i<n;i++) {
        cin >> u >> v;
        g[u].push_back(v);
        g[v].push_back(u);
    }
    dfs(1, 0);
    for(int i=1;i<=n;i++) {
        cin >> p;
        ans = 1, tmp = 1, m = dp[i].w % p * (dp[i].b % p) % p;
        if(k == 1) {
            cout << m % p << ' ';
            continue;
        } 
        for(int i=m;i>=m-k+1;i--) ans = i % p * ans % p;
        for(int i=1;i<=k;i++) {
            tmp = i % p * tmp % p;
        }
        ans = ans * qpow(tmp, p-2, p) % p;
        cout << ans << ' ';
    }
    return 0;
}
//dfs维护dp
void dfs(int u, int fa) {
    f[u] = fa, flag[u] = !flag[fa];
    for(auto v : g[u]) {
        if(v == fa) continue;
        dfs(v, u);
    }
    if(flag[u]) dp[u].b++;
    else dp[u].w++;
    dp[fa].b += dp[u].b;
    dp[fa].w += dp[u].w;
    return ;
}
//快速幂求解乘法逆元
int qpow(int a, int b, int p) {
    int res = 1;
    while(b) {
        if(b & 1) res = res * a % p;
        b >>= 1, a = a * a % p;
    }
    return res; 
} 

绫地宁宁天下第一可爱!