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;
}
完结撒花~
浙公网安备 33010602011771号