CF1254E Send Tree to Charlie
题意
讲不太清楚,看英文吧
cf
做法
在正式开始之前,我们先来玩一玩性质
首先考虑全\(0\)的情况,即本质不同的方案数
性质1:方案数并不为(n-1)!,即方案与结果不为双射
考虑一条边将树分为两个联通块,之间是互不影响的
结论1:方案数为\(\prod\limits (deg_i!)\)
考虑节点\(u\)的父节点与其父亲这条边已经选过
对于每种除\(u\)的儿子外的边固定时,\(u\)的儿子边的全排列决定了其对子树值的影响
ps:实际上这是无根树,但并不影响映射关系
性质2:若\(n\ge 2\),\(a_i\neq i\)
结论2:若知晓所有限制,\(\sum\limits dis(i,a_i)=2(n-1)\)
具体考虑\(a_v=u\)的限制,有以下结论
- 存在相对顺序边集\((u,t_1)(t_1,t_2)...(t_k,v)\)
- \((u,t_1)\)为\(u\)的第一条边
- \((t_k,v)\)为\(v\)的最后一条边
- \((t_{i-1},t_{i})(t_i,t_{i+1})\)为\(t_i\)严格顺序的边
我们可以依此建立顺序,合法的方案,对于某个点,有以下限制
- 不可破坏简单顺序
- 不可生成环,即为一种非自然的复杂顺序
- 若有严格顺序从第一条边到最后一条边,中间不可漏边
方案数,对于无限制的边随便选择顺序
题外话
这题很妙,虽然容易理解,但需要想满条件还是需要时间的,由于没出现什么算法,强行归到拓扑排序上了
code(std)
#include <bits/stdc++.h>
using namespace std;
const int mod = 1e9 + 7;
const int maxn = 500005;
int n;
vector <int> adj[maxn];
int a[maxn];
int dad[maxn];
int h[maxn];
vector <pair <int, int> > conditions[maxn];
int nxt[maxn], prv[maxn], seen[maxn];
void no(int ncase) {
cerr << ncase << endl;
cout << 0 << endl;
exit(0);
}
void dfs(int u) {
for (auto v: adj[u]) if (v != dad[u]) {
dad[v] = u;
h[v] = h[u] + 1;
dfs(v);
}
}
int cnt; ///total distance, must not be more than 2n-2
void go(int u, int v) {
if (u == v) no(0);
vector <int> from_u, to_v;
///naive LCA works here as long as we exit upon finding a conflict
from_u.push_back(n + 1); ///first edge (fake)
to_v.push_back(n + 2); ///last edge (fake)
while (h[u] > h[v]) {
from_u.push_back(u);
u = dad[u];
}
while (h[v] > h[u]) {
to_v.push_back(v);
v = dad[v];
}
while (u != v) {
from_u.push_back(u);
u = dad[u];
to_v.push_back(v);
v = dad[v];
}
from_u.push_back(u);
from_u.insert(from_u.end(), to_v.rbegin(), to_v.rend());
for (int i = 1; i + 1 < from_u.size(); ++i)
conditions[from_u[i]].push_back({from_u[i-1], from_u[i+1]});
cnt += from_u.size() - 3;
if (cnt > 2 * n - 2) no(0); ///important break
}
int main(void) {
ios_base::sync_with_stdio(0);
cin.tie(NULL);
cin >> n;
for (int i = 1; i < n; ++i) {
int u, v;
cin >> u >> v;
adj[u].push_back(v);
adj[v].push_back(u);
}
for (int i = 1; i <= n; ++i) {
adj[i].push_back(n + 1); ///first edge (fake)
adj[i].push_back(n + 2); ///last edge (fake)
}
for (int i = 1; i <= n; ++i) cin >> a[i];
if (n == 1) {
cout << 1 << endl;
exit(0);
}
dfs(1);
for (int i = 1; i <= n; ++i) if (a[i] != 0) go(i, a[i]);
///answer 0 if:
///1. there are 2 or more incoming/outgoing
///conditions to/from an edge, or
///2. there is a cycle, or
///3. first (n+1) is connected to last (n+2),
///but does not contain all other edges.
int ans = 1;
for (int i = 1; i <= n; ++i) {
///check case 1
for (auto edge: conditions[i]) {
int u = edge.first, v = edge.second;
if (nxt[u] && nxt[u] != v) no(1);
if (prv[v] && prv[v] != u) no(1);
nxt[u] = v;
prv[v] = u;
}
///check case 2
for (auto u: adj[i]) if (!seen[u]) {
seen[u] = 1;
int cur = nxt[u];
while (cur) {
if (cur == u) no(2);
if (seen[cur]) break;
seen[cur] = 1;
cur = nxt[cur];
}
}
///check case 3
if (nxt[n+1]) {
int cur = n + 1, all = 1;
while (cur) {
if (cur == n + 2) break;
++all;
cur = nxt[cur];
}
if (cur == n + 2 && all < adj[i].size()) no(3);
}
///all good - for now
int free = 0;
for (auto u: adj[i]) if (u <= n && !prv[u]) ///fake edges doesn't count
++free;
if (prv[n+2]) --free; ///connected to last edge => not free
for (int j = 1; j <= free; ++j) ans = 1ll * ans * j % mod;
///reset
for (auto u: adj[i]) nxt[u] = prv[u] = seen[u] = 0;
}
///no conflicts
cout << ans << endl;
return 0;
}
CF1254E Send Tree to Charlie的更多相关文章
- 应用监控CAT之cat-client源码阅读(一)
CAT 由大众点评开发的,基于 Java 的实时应用监控平台,包括实时应用监控,业务监控.对于及时发现线上问题非常有用.(不知道大家有没有在用) 应用自然是最初级的,用完之后,还想了解下其背后的原理, ...
- 深入详解美团点评CAT跨语言服务监控(三)CAT客户端原理
cat客户端部分核心类 message目录下面有消息相关的部分接口 internal目录包含主要的CAT客户端内部实现类: io目录包含建立服务端连接.重连.消息队列监听.上报等io实现类: spi目 ...
- 大众点评CAT开源监控系统剖析
参考文档: 大众点评的实时监控系统分析(一) CAT_source_analyze 透过CAT,来看分布式实时监控系统的设计与实现 深度剖析开源分布式监控CAT [分布式监控CAT] Client端源 ...
- [python]MS17-010自动化扫描脚本
一种是3gstudent分享的调用Nsa泄露的smbtouch-1.1.1.exe实现验证,另一种是参考巡风的poc.这里整合学习了下两种不同的方法. import os import fileinp ...
- 【转】大众点评CAT开源监控系统剖析
https://www.cnblogs.com/yeahwell/p/cat.html 参考文档: 大众点评的实时监控系统分析(一) CAT_source_analyze 透过CAT,来看分布式实时监 ...
- Flex之DataGrid和Tree控件的数据源XML格式
1.flex的完整代码: <?xml version="1.0" encoding="utf-8"?> <s:Application xmln ...
- [Webpack 2] Tree shaking with Webpack 2
The less code you can send to the browser, the better. The concept of tree shaking basically says th ...
- LINQ Expresstion Tree 表达式树
Expression trees represent code in a tree-like data structure, where each node is an expression, for ...
- Show tree of processes in linux
pstree(1): tree of processes - Linux man pagehttps://linux.die.net/man/1/pstree How to view process ...
随机推荐
- Linux命令行与Shell脚本编程大全
快来参加<Linux命令行与Shell脚本编程大全>学习吧,提升技能,展示自我. 点击链接即可进入学习:https://s.imooc.com/WTmCO6H 课程亮点适合零基础读者,从零 ...
- Python3(十) 函数式编程: 匿名函数、高阶函数、装饰器
一.匿名函数 1.定义:定义函数的时候不需要定义函数名 2.具体例子: #普通函数 def add(x,y): return x + y #匿名函数 lambda x,y: x + y 调用匿名函数: ...
- 如何重写object虚方法
在 C# 中 Object 是所有类的基类,所有的结构和类都直接或间接的派生自它.前面这段话可以说所有的 C# 开发人员都知道,但是我相信其中有一部分程序员并不清楚甚至不知道我们常用的 ToStrin ...
- vue垂死挣扎系列(一)——vue-cli快速搭建
项目安装(windows10安装环境+vue-cli 2.x) 安装node 在官网上下载稳定版本的node node.js官网 一路傻瓜安装 测试是否安装成功 cmd中node --version ...
- java设计模式学习笔记--开闭原则
基本介绍 1.开闭(ocp)原则时编程中最基础.最重要的设计原则 2.一个软件实体如类.木块和函数应该对扩展开放,对修改关闭.用抽象构建框架,用实现扩展细节.即对提供方开放,对使用方关闭. 3.当软件 ...
- 编译Qualcomm的Hexagon exampls错误
在下载了Qualcomm的Hexagon SDK 351版本之后,想跑里面的examples,然后参照文档的说,比如在examples/common/sobel3x3_v60目录下面,先执行了SDK根 ...
- maven 听视频笔记
使用 pom.xml 配置 收藏 所听视频来源: https://www.bilibili.com/video/av54119831?p=8 视频: maven idea 配置服务器 tomcat ...
- vue自定义分页组件---切图网
vue2.5自定义分页组件 Pagination.vue,可设置每页显示条数,带跳转框直接跳转到相应页面,亲测有用.目前很多框架自带有分页组件比如elementUI,不过在面对一个拿到PSD稿,然后重 ...
- 小白的linux笔记11:放弃gitbook,转战Sphinx
gitbook生成的html目录不折叠且链接失效 装好了gitbook和nodejs,本以为可以安心的做电子书了. 谁想到gitbook慢的一P,而且导出来的html目录不折叠,最关键的是链接有问题, ...
- 秋水逸冰实用Linux脚本收藏
秋水逸冰的脚本非常受欢迎,奈何其本人博客已经不能访问(目前是这样,不知道别的地区是否能访问),实际上GitHub上他本人一直在维护,因为某些原因不放出他本人的GitHub地址.截止到2019年12月1 ...