D:(求联通分量个数)
题意:有两个数n,k,分别代表树的节点个数和一个点集的点的数量
给你一棵树,树的边有黑色的有红色的,定义满足要求的点集为:这个点集有k个点,并且点集中一个点到达其余点的路径中,必须有一条边是黑色的,求满足要求的点集的数量
分析:
emmm其实第一眼看到这个题是没有思路的,但是后来发现,点集总数量为n^k(从n个点中抽取k次),我们可以用 base=n^k减去不满足条件的点集数量就ok
然后我们来分析一下什么样的点集是不满足条件的:
已知满足条件的点集是路径上至少有一条黑色边的,所以不满足条件的点集是:点集中任意两点的最短路径的边都是红色的,因此,不满足条件的点集所在的联通分量的边都是红色的,所以不满足的点集的个数就是:
定义每个联通分量大小为Pi,数量为 sun(Pi^k)
所以我们只要移除黑色边,求红色边构成图的联通分量的个数以及大小就OK
代码如下:
1 #include<bits/stdc++.h> 2 #define ll long long 3 using namespace std; 4 const int maxn=1e5+5; 5 const int mod=1e9+7; 6 bool vis[maxn]; 7 vector<int>G[maxn]; 8 int n,k; 9 int dfs(int v) 10 { 11 vis[v]=1; 12 int t=1; 13 for(int i=0;i<G[v].size();++i) 14 { 15 int to=G[v][i]; 16 if(vis[to]) continue; 17 t+=dfs(to); 18 } 19 return t; 20 } 21 ll pow(ll base) 22 { 23 int t=base; 24 for(int i=1;i<k;++i) 25 { 26 base*=t; 27 base%=mod; 28 } 29 return base; 30 } 31 int main() 32 { 33 cin>>n>>k; 34 for(int i=1;i<n;++i) 35 { 36 int a,b,c; 37 cin>>a>>b>>c; 38 if(c==0) G[a].push_back(b),G[b].push_back(a); 39 } 40 int base=pow(n); 41 int sub=0; 42 for(int i=1;i<=n;++i) 43 { 44 if(vis[i]==0) sub+=pow(dfs(i)); 45 sub%=mod; 46 } 47 printf("%d",base-sub>=0?base-sub:base-sub+mod); 48 }