CF1824B2 LuoTianyi and the Floating Islands (Hard Version)

传送门
首先当\(k\)为奇数时,若一个点想为好点,必须他自己就是岛屿之一,所以\(k\)为奇数时答案一定是\(1\)
接着考虑\(k\)为偶数时怎么求好点数。我们发现,若一个点为好点,则当其延某一条边移动一次得到的点的答案一定不能更优,否则这次移动得到的点才是好点。也就是说,对于好点所连的所有边,好点这一侧的岛屿数量必须大于等于另一侧的岛屿数量,也就说,我们可以算一个点在多少个方案中作为好点出现,出现的次数即\(C_{n}^{k}-\sum_{v} \sum_{j=\frac{k}{2} +1}^{min(k,siz_v)} C_{siz_v}^{j}\)
但是这样统计答案是\(O(n^2)\)的复杂度。
注意到所有的好点一定是连续出现的,即所有的好点一定组成了一个连通块,而这个连通块一定是树。所以我们可以定义好边为其两侧的岛屿数量相同的边,这样好点的数量就是好边的数量加\(1\),因为树中点的数量为边的数量加\(1\)
而好边的数量是好算的,即\(\sum C_{siz_u}^{\frac{k}{2}} C_{siz_v}^{\frac{k}{2}}\)
最后输出答案记得除以\(C_{n}^{k}\)

当某种点的数量/贡献难求时,可以考虑转化为求边的数量/贡献

#include<bits/stdc++.h>
#define int long long

using namespace std;

const int N = 5e5 + 10;
const int inf = 1e18 + 10;
const int mod = 1e9 + 7;
int n,m,fac[N],inv[N],siz[N],ans;
vector<int> g[N];

int quickMul(int x,int k) {
    int res = 1;
    while(k) {
        if(k & 1) res = res * x % mod;
        x = x * x % mod;
        k >>= 1;
    }
    return res;
}

int C(int n,int m) {
    return fac[n] * inv[m] % mod * inv[n - m] % mod;
}

void dfs(int u,int fa) {
    siz[u] = 1;
    for(auto i : g[u]) {
        if(i == fa) continue;
        dfs(i,u);
        siz[u] += siz[i];
        if(siz[i] >= m / 2 && n - siz[i] >= m / 2) ans = (ans + C(siz[i],m / 2) * C(n - siz[i],m / 2) % mod) % mod;
    }
    // if(n - siz[u] >= m / 2 + 1) ans = (ans + get_num(n - siz[u])) % mod;
}

void solve() {
    cin >> n >> m;
    for(int u,v,i = 1;i < n;i++) {
        cin >> u >> v;
        g[u].push_back(v);
        g[v].push_back(u);
    }
    if(m & 1) return (void)(cout << 1 << '\n');
    dfs(1,0);
    // ans = ((n * C(n,m) % mod - ans) % mod + mod) % mod;
    // cout << ans << ' ' << C(n,m) << '\n';
    cout << (ans * quickMul(C(n,m),mod - 2) % mod + 1) % mod << '\n';
}

signed main() {
    ios::sync_with_stdio(0);
    cin.tie(0);cout.tie(0);
    fac[0] = 1;
    for(int i = 1;i < N;i++) fac[i] = fac[i - 1] * i % mod;
    inv[N - 1] = quickMul(fac[N - 1],mod - 2);
    for(int i = N - 2;i >= 0;i--) inv[i] = inv[i + 1] * (i + 1) % mod;
    int t = 1;
    while(t--) solve();
    
    return 0;
}
posted @ 2025-08-23 16:39  孤枕  阅读(8)  评论(0)    收藏  举报