Codeforce Round #548(Div2)

  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 }

猜你喜欢

转载自www.cnblogs.com/codeoosacm/p/10682841.html
今日推荐