P10912 [蓝桥杯 2024 国 B] 数星星

P10912 [蓝桥杯 2024 国 B] 数星星

题意简介

给定一棵 \(n\) 个节点的树和 \(L,R\),询问有多少个子图 \(G\),满足该子图是一棵树,树中存在一个节点 \(u\),其度数为 \(|V_G|-1\),且 \(|V_G| \in [L,R]\)

思路

观察到每一个满足条件的子图 \(G\)中,\(u\) 的度数为 \(|V_G|-1\) 意味着 \(u\)\(G\) 中其他所有点均有一条连边,故 \(G\) 必然是一张菊花图

那么对于每一个节点 \(u\),设其度数为 \(deg_u\),对于 \(\forall m \in [1,deg_u+1]\),该节点可以对大小为 \(m\) 的星星数量产生 \(C_{deg_u}^{m-1}\) 的贡献。

如果直接遍历每一个节点分别统计,时间复杂度将会达到 \(O(n \times (R-L+1))\)\(O(n^2)\) 级别,对于 \(N=1 \times 10^5\) 显然会超时,所以我们考虑预处理出 \(num_i\) 表示度数为 \(i\) 的节点数量,这样在算到度数相同的节点时可以直接将贡献乘上一个 \(num_i\),此时设有 \(t\) 种不同的 \(deg_u\)\(\Sigma_{i=1}^t \leq n\),即 \(t\) 一定不会超过 \(\sqrt{n}\),最终的时间复杂度为 \(O(n\sqrt{n})\)

Code

//度为i的节点可以为节点数为j的星星数提供C(i,j-1)的贡献
#include<iostream>
#define IOS ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
using namespace std;
const int N=1e5+5;
const int MOD=1e9+7;
int n,L,R,degree[N],num[N];
long long fac[N],inv[N],ans=0;
long long quick_pow(long long a,long long b)
{
    long long base=a,res=1;
    while(b)
    {
        if(b&1) res=res*base%MOD;
        base=base*base%MOD;
        b>>=1;
    }
    return res;
}
void init(int n)
{
    fac[0]=1;
    for(int i=1;i<=n;i++)
        fac[i]=fac[i-1]*i%MOD;
    inv[n]=quick_pow(fac[n],MOD-2);
    for(int i=n;i>=1;i--)
        inv[i-1]=inv[i]*i%MOD;
}
long long C(int n,int m)
{
    if(m<0||m>n) return 0;
    return fac[n]*inv[m]%MOD*inv[n-m]%MOD;
}
int main()
{
    IOS;
    cin>>n;
    init(n);
    for(int i=1;i<n;i++)
    {
        int u,v;
        cin>>u>>v;
        degree[u]++,degree[v]++;
    }
    cin>>L>>R;
    for(int i=1;i<=n;i++)
        num[degree[i]]++;
    for(int i=max(1,L-1);i<=n;i++)
    {
        if(num[i]>0)
            for(int j=L;j<=min(R,i+1);j++)
                ans=(ans+num[i]*C(i,j-1)%MOD)%MOD;
    }
    cout<<ans<<'\n';
    return 0;
}

完结撒花~

posted @ 2025-09-05 18:21  FallingGardenia  阅读(8)  评论(0)    收藏  举报