题面:

传送门

题目描述:

给出有n个节点的树,整数k。题目要求找长度为k,符合规则(good序列)的“点序列”(由节点构成的序列)个数有多少?规则如下:
  • 1.走一条出发点为a1,终点为ak的一条路(允许重复边,重复点)
  • 2.从a1开始,通过最短路径走到a2,然后从a2通过最短路径走到a3,以此类推,直到走到终点
  • 3.如果在上述过程中,至少经过一条“黑边”,则这个序列是good的
 

题目分析:

这道题直接分析确实挺难,难在哪里呢?我们看看这个good序列要满足什么条件:
1.走一条路:这里要注意的就是可以重复点,其他没什么可以引起注意的地方
2.从a1走到a2,a2走到a3......如果这个过程经过了黑边,这个序列就是good序列:
所以刚开始我们的想法是:
找一条黑边两端的端点,然后看看包含这两个端点的序列有多少个,再减去重复的。
 
但是,想法很美好,情况很复杂,我刚开始就是这么想的。后面发现越来越不对劲,就重新看了一下题目,发现了一些重要的突破口:
1.题目的good序列是“至少”经过一条黑边,注意,这里的用词是用“至少”。
2.原题目的最后还提醒了:总共有n^k个序列,算其中good序列有多少个。
然后我就想到了:既然good序列这么难算,不如算算bad序列?
bad序列规则:第一点和第二点不变,第三点:如果在上述过程中,没有经过一条“黑边”,则这个序列是bad的。也就是说:
如果在上述过程中,经过所有的边都是“红边”(包括没经过边),则这个序列是bad的。
 
这时问题就变得好解决一些了:
只要找出所有的bad序列,通过n^k-bad,就可以间接求出good序列。而bad序列有什么特点?上面文字已经介绍完毕,下面我们观察一下图:
这个图中,由上面的bad文字定义可知:bad序列肯定是在三个分开的集合取:{1,2,4,6},{5},{3,7}。进一步发现:在一个集合的内部是连通的,而且互相到达绝不经过黑边。对于三个集合来说,它们直接被“黑边”分隔开了。也就是说:可以通过去掉“黑边”得到上面的集合:
其实也就是有多少个连通分支,这个用dfs很好解决。
 
得到了这个集合后,就是怎么算的问题了。举个例子:对于这个集合:{1,2,4,6},我们只需要选k次就得到了bad序列的总数,也就是4^k。(不明白的同学可以这样想:要得到长度为k的bad序列,也就是要确定k个位置的值。每个位置都可以选4个元素而保证一定是bad序列,根据组合数学的分步原理,就是4^k个bad序列)。每一个集合我们都算出它们的bad序列的个数,加起来就是总的bad序列个数。
 
 
 
AC代码:
#include <cstdio>
#include <vector>
using namespace std;
const int maxn = 1e5+5;
const int mod = 1e9+7;
int k;
long long n;
vector<int> G[maxn]; //存图
long long cnt[maxn]; //统计每个集合元素个数
int vis[maxn]; //标记/判断i属于哪个集合 void dfs(int u, int num){
if(vis[u]) return;
vis[u] = num; //标记
for(int i = 0; i < G[u].size(); i++){
dfs(G[u][i], num);
}
} int main(){
scanf("%lld %d", &n, &k);
int u, v;
int is_b;
for(int i = 0; i < n-1; i++){
scanf("%d%d%d", &u, &v, &is_b);
if(!is_b){ //如果不是黑边就加入到图中
G[u].push_back(v);
G[v].push_back(u);
}
} for(int i = 1; i <= n; i++){
if(!vis[i]) dfs(i, i);
} for(int i = 1; i <= n; i++){
cnt[vis[i]]++; //统计每个集合的元素个数
} long long bad = 0;
for(int i = 1; i <= n; i++){
long long ans = 1;
if(cnt[i]){ //如果集合存在
for(int j = 1; j <= k; j++){ //算cnt[i]的k次方
ans = ans*cnt[i]%mod;
}
bad = (bad+ans)%mod;
}
} long long all = 1; //算n的k次方
for(int i = 1; i <= k; i++){
all = all*n%mod;
} printf("%lld\n", (all-bad+mod)%mod); //因为all-bad可能为负数(计算时边取模边算), 所以, 要先加个mod再取模
return 0;
}
 
 
 
 

Codeforces Round #548 C. Edgy Trees的更多相关文章

  1. Codeforces Round 548 (Div. 2)

    layout: post title: Codeforces Round 548 (Div. 2) author: "luowentaoaa" catalog: true tags ...

  2. C. Edgy Trees Codeforces Round #548 (Div. 2) 并查集求连通块

    C. Edgy Trees time limit per test 2 seconds memory limit per test 256 megabytes input standard input ...

  3. CodeForces Round #548 Div2

    http://codeforces.com/contest/1139 A. Even Substrings You are given a string s=s1s2…sns=s1s2…sn of l ...

  4. Codeforces Round #548

    没打,简单补档 C.Edgy Trees 容斥,把黑边断掉数联通块,每个联通块贡献$siz^k$ #include<cstdio> #include<cstring> #inc ...

  5. C. Edgy Trees Codeforces Round #548 (Div. 2) 【连通块】

    一.题面 here 二.分析 这题刚开始没读懂题意,后来明白了,原来就是一个数连通块里点数的问题.首先在建图的时候,只考虑红色路径上的点.为什么呢,因为为了不走红色的快,那么我们可以反着想只走红色的路 ...

  6. Codeforces Round #548 (Div. 2) C. Edgy Trees

    You are given a tree (a connected undirected graph without cycles) of 

  7. Codeforces Round #548 (Div. 2) F splay(新坑) + 思维

    https://codeforces.com/contest/1139/problem/F 题意 有m个人,n道菜,每道菜有\(p_i\),\(s_i\),\(b_i\),每个人有\(inc_j\), ...

  8. Codeforces Round #548 (Div. 2) E 二分图匹配(新坑) or 网络流 + 反向处理

    https://codeforces.com/contest/1139/problem/E 题意 有n个学生,m个社团,每个学生有一个\(p_i\)值,然后每个学生属于\(c_i\)社团, 有d天,每 ...

  9. Codeforces Round #548 (Div. 2) C dp or 排列组合

    https://codeforces.com/contest/1139/problem/C 题意 一颗有n个点的树,需要挑选出k个点组成序列(可重复),按照序列的顺序遍历树,假如经过黑色的边,那么这个 ...

随机推荐

  1. IFIX 数据源 节点 标签 域名

    一个动画,前景颜色 数据源如上图 点 ,,, 进入选择界面,如下 Fix32  应该是统一的前缀,自动添加上的 然后就是我们的节点名字,启动ifix的时候显示的那个节点名字 标签应该就是我们的 变量/ ...

  2. console.dir()可以显示一个对象所有的属性和方法

    console.dir()可以显示一个对象所有的属性和方法 具体方法如下:

  3. 钉钉 & URL Scheme & Universal Link & Deep Link

    钉钉 & URL Scheme & Universal Link & Deep Link DD link https://www.cnblogs.com/xgqfrms/p/1 ...

  4. Renice INC:不同颜色的酒帽所代表的意义

    酒帽就是酒瓶上方的热缩胶帽/锡帽/蜡封,也就是开瓶前要割掉的那一层保护物,所有的法国酒在酒帽上,都会有一个圆形贴纸,除了有不同颜色外,上面还有一串号码,有可能很多人在喝酒时都不会对这个酒帽有更多的在意 ...

  5. React Native选择器组件-react-native-slidepicker

    react-native-slidepicker 一个纯 JavaScript 实现的的 React Native 组件,用于如地址,时间等分类数据选择的场景. github: https://git ...

  6. Java并发包源码学习系列:同步组件CountDownLatch源码解析

    目录 CountDownLatch概述 使用案例与基本思路 类图与基本结构 void await() boolean await(long timeout, TimeUnit unit) void c ...

  7. RecycleView 点击事件监听

    1.定义RecycleView 监听接口类 1 package com.example.*****; 2 3 import android.view.View; 4 5 public interfac ...

  8. 力扣832. 翻转图像-C语言实现-简单题

    题目 传送门 文本 给定一个二进制矩阵 A,我们想先水平翻转图像,然后反转图像并返回结果. 水平翻转图片就是将图片的每一行都进行翻转,即逆序.例如,水平翻转 [1, 1, 0] 的结果是 [0, 1, ...

  9. 双重检验锁模式为什么要使用volatile?

    并发编程情况下有三个要点:操作的原子性.可见性.有序性. volatile保证了可见性和有序性,但是并不能保证原子性. 首先看一下DCL(双重检验锁)的实现: public class Singlet ...

  10. .NET测试--模拟框架NSubstitute

    .NET测试--模拟框架NSubstitute .NET测试 NSubstitute在GitHub的开源地址:https://github.com/nsubstitute/nsubstitute/do ...