cf-div.2-872.D1

发布时间 2023-05-09 10:12:04作者: 安潇末痕

题目链接:https://codeforces.com/contest/1825/problem/D1

赛时没过的题,主要不会的点在于k=2的情况。

思路:当k = 1 或者 k = 3 时,可以证明答案永远为1,可以画个图看看。
当k = 2 时,答案为所有选中的两个点的距离加一之和。
一共有n(n-1)/2种选法,直接暴力必TLE。
所以我们考虑每条边对答案的贡献。
假设有一条边x,它左边有a个点,右边有b个点,这条边就可以做出a
b的贡献。
不要忘了,答案为所有选中的两个点的距离加一之和,所以答案等于所有边的贡献+n*(n-1)/2。
代码:

#include <bits/stdc++.h>
using namespace std;
const int N = 200010,mod = 1e9+7;
vector<int>M[N];
int h[N],ne[2*N],num[2*N],idx;
int sz[N],n,k;
long long ans;
long long qmod(long long x,long long y){
    long long ans = 1;
    while(y){
        if (y&1) ans = ans*x%mod;
        x = x*x%mod;
        y = y>>1;
    }
    return ans;
}
void add(int x,int y){
    num[idx] = y,ne[idx] = h[x],h[x] = idx++;
}
void dfs(int u,int fa){
    M[u].push_back(1);
    sz[u] = 1;
    for (int i=h[u];i!=-1;i=ne[i]){
        int v = num[i];
        if (v==fa) continue;
        dfs(v,u);
        ans = (ans+1ll*sz[v]*(n-sz[v]))%mod;
        sz[u] += sz[v];
    }
}
void solve(){
    cin>>n>>k;
    idx = 0;
    memset(h,-1,sizeof(h));
    for (int i=1;i<n;i++){
        int x,y;
        cin>>x>>y;
        add(x,y);
        add(y,x);
    }
    if (k==1||k==3) cout<<1<<'\n';
    else{
        dfs(1,-1);
        long long sum = 1ll*n*(n-1)/2;
        sum = sum%mod;
        ans = (ans+sum)*qmod(sum,mod-2)%mod;
        cout<<ans<<'\n';
    }
}
int main(){
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    int T;
    T = 1;
    while(T--) solve();
    return 0;
}