Solution -「JOISC 2020」「UOJ #509」迷路的猫
\(\mathcal{Decription}\)
Link.
这是一道通信题。
给定一个 \(n\) 个点 \(m\) 条边的连通无向图与两个限制 \(A,B\)。
程序 Anthony 需要用 \(0\sim A-1\) 共 \(A\) 中颜色为无向图的每条边染色。
程序 Catherine 需要帮助一只猫行走:已知猫所在结点邻接每种颜色的边的数量,你需要告诉猫走哪种颜色的边(但不能让它走特定某条),并保证猫从起点 \(s\) 到 \(0\) 所走的距离不超过两点最短距离 \(+B\)。
\(n,m\le2\times10^4\),\(A,B\) 满足 \(A\ge 3,B\ge0\) 或 \(A\ge 2,B\ge6\) 的一种,满足后者时,\(m=n-1\)。
\(\mathcal{Solution}\)
就**离谱好吗 qwq!
\(\mathcal{Anthony}\)
嘛……不难看出两种情况是割裂的,分类讨论咯。
\(\mathcal{Part~1}\)
\(A=3,B=0\),相当于要求我们必须走最短路。
考虑从 \(0\) 出发,用 BFS 将图分层,设结点到 \(0\) 的距离为 \(dist_i\) 的点都在第 \(dist_i\) 层。注意猫是要从终点向回走,所以我们应当把连接上一层的边和连接同层或连接下一层的边区分开来。一种方法是令 \(color(u,v)=\min\{dist_u,dist_v\}\bmod3\),则一个点的邻接边颜色不超过两种,判一判那条边是向上层的即可。
\(\mathcal{Part~1-Code}\)
namespace Task1 {
bool vis[MAXN + 5];
inline vecint main ( vecint U, vecint V ) {
std::queue<int> que;
que.push ( 0 ), vis[0] = true;
while ( ! que.empty () ) {
int u = que.front (); que.pop ();
for ( pii v: graph[u] ) if ( ! vis[v.first] ) {
dist[v.first] = dist[u] + 1;
que.push ( v.first ), vis[v.first] = true;
}
}
vecint ret ( m );
for ( int i = 0; i < m; ++ i ) ret[i] = std::min ( dist[U[i]], dist[V[i]] ) % 3;
return ret;
}
} // namespace RybyA::Task1.
\(\mathcal{Part~2}\)
\(A=2,B=6\),一棵树。如果以 \(0\) 为根,无脑往上走就好啦。问题在于如何将一个结点的父亲与儿子们区分开来。
若 \(d_u>2\),即 \(u\) 有多于一个儿子,那么令向儿子们的颜色相同,向父亲的颜色与之区分即可。
若 \(d_u=2\),即链。怎么区分上下呢……我们考虑用一串循环颜色构造一个“通行方向箭头”,这样能让猫在走了一定的远路之后,可以认出箭头的指向继而调转方向。可见,“箭头”需要满足:所有由其循环同构串作为循环节的串不存在长度 \(\ge\lfloor\frac{B}2\rfloor+2\) 的回文子串。说人话呢,算上起点,猫最多用长度为 \(\lfloor\frac{B}2\rfloor+1\) 的链“认路”,那么猫最多看到 \(\lfloor\frac{B}2\rfloor+2\) 条边的颜色。如果颜色是回文,还是认不出路,就失败啦!
一种可行的“箭头”是 0 0 1 1 0 1,恰好满足条件(0 1 1 0 为最长回文,长度为 \(4\))。
\(\mathcal{Part~2-Code}\)
namespace Task2 {
const int dir[] { 0, 0, 1, 1, 0, 1 };
vecint ans;
inline void direct ( const int u, const int f, const int clen, const int curc ) {
// clen为链长(不在链上则为0),curc是若u不在链上时需要为向儿子的边染的颜色。
if ( ! ~ f ) {
for ( pii v: graph[u] ) {
ans[v.second] = 0;
direct ( v.first, u, ( int ) graph[u].size () == 1, 1 );
}
return ;
}
if ( ( int ) graph[u].size () == 2 ) {
for ( pii v: graph[u] ) if ( v.first ^ f ) {
ans[v.second] = dir[clen % 6];
direct ( v.first, u, clen + 1, ans[v.second] ^ 1 );
}
return ;
}
for ( pii v: graph[u] ) if ( v.first ^ f ) {
ans[v.second] = curc;
direct ( v.first, u, 0, ans[v.second] ^ 1 );
}
}
inline vecint main () {
ans.resize ( m );
direct ( 0, -1, 0, 0 );
return ans;
}
} // namespace RybyA::Task2.
\(\mathcal{Catherine}\)
大 模 拟 !
\(\mathcal{Part~1}\)
显。(因为下一部分太复杂 qwq……
\(\mathcal{Part~1-Code}\)
namespace Task1 {
inline int main ( vecint Y ) {
// last 为上一次走的颜色,Part2同理。
int cnt = 0;
if ( ~ last ) ++ Y[last];
for ( int y: Y ) cnt += !! y;
if ( cnt == 1 ) last = Y[2] ? 2 : !! Y[1];
else {
for ( int i = 0; i < 3; ++ i ) {
if ( ! Y[i] ) {
last = ( i + 1 ) % 3;
break;
}
}
}
return last;
}
} // namespace RybyC::Task1.
\(\mathcal{Part~2}\)
首先,记录是否已经定好方向。若已定向,无脑走即可。若未定向且当前点仍在链上,则全局用一个 std::vector 记下经过的箭头颜色。当 std::vector 的 size() 为 \(5\),就一定可以定向了,打表判一判即可。
反正……亿点细节,见代码吧(绝望 qwq。
\(\mathcal{Part~2-Code}\)
namespace Task2 {
const int down[6][5] {
{ 0, 0, 1, 1, 0 },
{ 0, 1, 1, 0, 1 },
{ 1, 1, 0, 1, 0 },
{ 1, 0, 1, 0, 0 },
{ 0, 1, 0, 0, 1 },
{ 1, 0, 0, 1, 1 }
};
vecint chain;
bool directed;
inline int main ( vecint Y ) { // 注意需要在外部用返回值更新last。
if ( ! ~ last ) {
if ( Y[0] + Y[1] == 2 ) {
if ( ! Y[1] ) {
chain.push_back ( 0 ), chain.push_back ( 0 );
return 0;
} else if ( ! Y[0] ) {
chain.push_back ( 1 ), chain.push_back ( 1 );
return 1;
} else {
chain.push_back ( 1 ), chain.push_back ( 0 );
return 0;
}
}
if ( ! Y[0] ) return directed = true, 1;
if ( ! Y[1] ) return directed = true, 0;
return directed = true, Y[1] == 1;
}
if ( ! Y[0] && ! Y[1] ) return directed = true, -1;
if ( ! directed ) {
if ( Y[0] + Y[1] > 1 ) {
directed = true;
if ( ! Y[0] || ! Y[1] ) return -1;
return ! last;
}
chain.push_back ( Y[1] );
if ( chain.size () == 5 ) {
bool downing = false; directed = true;
for ( int i = 0; ! downing && i < 6; ++ i ) {
int j = 0;
for ( ; j < 5; ++ j ) if ( down[i][j] ^ chain[j] ) break;
if ( j == 5 ) downing = true;
}
if ( downing ) return -1;
}
return chain.back ();
} else {
if ( ! Y[0] ) return 1;
if ( ! Y[1] ) return 0;
++ Y[last];
return Y[1] == 1;
}
}
} // namespace RybyC::Task2.
} // namespace RybyC.
\(\mathcal{Code}\)
// Anthony.cpp
#include <queue>
#include <vector>
#include <iostream>
#include "Anthony.h"
#ifndef vecint
#define vecint std::vector<int>
#endif
#ifndef pii
#define pii std::pair<int, int>
#endif
namespace RybyA {
const int MAXN = 2e4;
int n, m, dist[MAXN + 5];
std::vector<pii> graph[MAXN + 5];
namespace Task1 {
bool vis[MAXN + 5];
inline vecint main ( vecint U, vecint V ) {
std::queue<int> que;
que.push ( 0 ), vis[0] = true;
while ( ! que.empty () ) {
int u = que.front (); que.pop ();
for ( pii v: graph[u] ) if ( ! vis[v.first] ) {
dist[v.first] = dist[u] + 1;
que.push ( v.first ), vis[v.first] = true;
}
}
vecint ret ( m );
for ( int i = 0; i < m; ++ i ) ret[i] = std::min ( dist[U[i]], dist[V[i]] ) % 3;
return ret;
}
} // namespace RybyA::Task1.
namespace Task2 {
const int dir[] { 0, 0, 1, 1, 0, 1 };
vecint ans;
inline void direct ( const int u, const int f, const int clen, const int curc ) {
if ( ! ~ f ) {
for ( pii v: graph[u] ) {
ans[v.second] = 0;
direct ( v.first, u, ( int ) graph[u].size () == 1, 1 );
}
return ;
}
if ( ( int ) graph[u].size () == 2 ) {
for ( pii v: graph[u] ) if ( v.first ^ f ) {
ans[v.second] = dir[clen % 6];
direct ( v.first, u, clen + 1, ans[v.second] ^ 1 );
}
return ;
}
for ( pii v: graph[u] ) if ( v.first ^ f ) {
ans[v.second] = curc;
direct ( v.first, u, 0, ans[v.second] ^ 1 );
}
}
inline vecint main () {
ans.resize ( m );
direct ( 0, -1, 0, 0 );
return ans;
}
} // namespace RybyA::Task2.
} // namespace RybyA.
vecint Mark ( const int N, const int M, const int A, const int B, vecint U, vecint V ) {
RybyA::n = N, RybyA::m = M;
for ( int i = 0; i < M; ++ i ) {
RybyA::graph[U[i]].push_back ( { V[i], i } );
RybyA::graph[V[i]].push_back ( { U[i], i } );
}
if ( A > 2 ) return RybyA::Task1::main ( U, V );
return RybyA::Task2::main ();
}
// main () {}
// Catherine.cpp
#include <vector>
#include <assert.h>
#include "Catherine.h"
#ifndef vecint
#define vecint std::vector<int>
#endif
#ifndef pii
#define pii std::pair<int, int>
#endif
namespace RybyC {
bool type;
int last;
namespace Task1 {
inline int main ( vecint Y ) {
int cnt = 0;
if ( ~ last ) ++ Y[last];
for ( int y: Y ) cnt += !! y;
if ( cnt == 1 ) last = Y[2] ? 2 : !! Y[1];
else {
for ( int i = 0; i < 3; ++ i ) {
if ( ! Y[i] ) {
last = ( i + 1 ) % 3;
break;
}
}
}
return last;
}
} // namespace RybyC::Task1.
namespace Task2 {
const int down[6][5] {
{ 0, 0, 1, 1, 0 },
{ 0, 1, 1, 0, 1 },
{ 1, 1, 0, 1, 0 },
{ 1, 0, 1, 0, 0 },
{ 0, 1, 0, 0, 1 },
{ 1, 0, 0, 1, 1 }
};
vecint chain;
bool directed;
inline int main ( vecint Y ) {
if ( ! ~ last ) {
if ( Y[0] + Y[1] == 2 ) {
if ( ! Y[1] ) {
chain.push_back ( 0 ), chain.push_back ( 0 );
return 0;
} else if ( ! Y[0] ) {
chain.push_back ( 1 ), chain.push_back ( 1 );
return 1;
} else {
chain.push_back ( 1 ), chain.push_back ( 0 );
return 0;
}
}
if ( ! Y[0] ) return directed = true, 1;
if ( ! Y[1] ) return directed = true, 0;
return directed = true, Y[1] == 1;
}
if ( ! Y[0] && ! Y[1] ) return directed = true, -1;
if ( ! directed ) {
if ( Y[0] + Y[1] > 1 ) {
directed = true;
if ( ! Y[0] || ! Y[1] ) return -1;
return ! last;
}
chain.push_back ( Y[1] );
if ( chain.size () == 5 ) {
bool downing = false; directed = true;
for ( int i = 0; ! downing && i < 6; ++ i ) {
int j = 0;
for ( ; j < 5; ++ j ) if ( down[i][j] ^ chain[j] ) break;
if ( j == 5 ) downing = true;
}
if ( downing ) return -1;
}
return chain.back ();
} else {
if ( ! Y[0] ) return 1;
if ( ! Y[1] ) return 0;
++ Y[last];
return Y[1] == 1;
}
}
} // namespace RybyC::Task2.
} // namespace RybyC.
void Init ( int A, int B ) { RybyC::last = -1, RybyC::type = A > 2; }
int Move ( vecint Y ) {
if ( RybyC::type ) return RybyC::Task1::main ( Y );
else {
int t = RybyC::Task2::main ( Y );
if ( ~ t ) RybyC::last = t;
return t;
}
}
// main () {}
Solution -「JOISC 2020」「UOJ #509」迷路的猫的更多相关文章
- 「JOISC 2020 Day2」变态龙之色 题解
题目传送门 注意 同性必定不同色 必有一个同色异性,且不相互不喜欢 Solution 我们发现,我们问题比较大的就是如何确定性别问题.我们可以一个一个加进去,在原来已经确定了的二分图上增加新的性别关系 ...
- 「JOISC 2020 Day1」汉堡肉
我终于学会打开机房的LOJ了! description LOJ3272 有\(n(n<=2*10^5)\)个矩形,让你找\(k(k<=4)\)个点可以覆盖所有矩形(点可重复),输出一种方案 ...
- 「JOISC 2020 Day4」首都城市
题目 点这里看题目. 分析 做法比较容易看出来.我们对于每个城市,找出那些 " 如果这个城市在首都内,则必须在首都内的其它城市 " ,也就是为了让这个城市的小镇连通而必须选 ...
- 「JOISC 2014 Day1」 历史研究
「JOISC 2014 Day1」 历史研究 Solution 子任务2 暴力,用\(cnt\)记录每种权值出现次数. 子任务3 这不是一个尺取吗... 然后用multiset维护当前的区间,动态加, ...
- Loj #2731 「JOISC 2016 Day 1」棋盘游戏
Loj 2731 「JOISC 2016 Day 1」棋盘游戏 JOI 君有一个棋盘,棋盘上有 \(N\) 行 \(3\) 列 的格子.JOI 君有若干棋子,并想用它们来玩一个游戏.初始状态棋盘上至少 ...
- 「JOISC 2019 Day3」穿越时空 Bitaro
「JOISC 2019 Day3」穿越时空 Bitaro 题解: 不会处理时间流逝,我去看了一眼题解的图,最重要的转换就是把(X,Y)改成(X,Y-X)这样就不会斜着走了. 问题变成二维平面上 ...
- 【LOJ】#3036. 「JOISC 2019 Day3」指定城市
LOJ#3036. 「JOISC 2019 Day3」指定城市 一个点的可以dp出来 两个点也可以dp出来 后面的就是在两个点的情况下选一条最长的链加进去,用线段树维护即可 #include < ...
- 【LOJ】#3034. 「JOISC 2019 Day2」两道料理
LOJ#3034. 「JOISC 2019 Day2」两道料理 找出最大的\(y_{i}\)使得\(sumA_{i} + sumB_{y_i} \leq S_{i}\) 和最大的\(x_{j}\)使得 ...
- 【LOJ】#3032. 「JOISC 2019 Day1」馕
LOJ#3032. 「JOISC 2019 Day1」馕 处理出每个人把馕切成N段,每一段快乐度相同,我们选择第一个排在最前的人分给他的第一段,然后再在未选取的的人中选一个第二个排在最前的切一下,并把 ...
随机推荐
- springboot 配置 swagger2
1.pom.xml 添加依赖 <!--swagger2 依赖--> <dependency> <groupId>io.springfox</groupId&g ...
- [ vue ] xxxProject项目杂记
2020.4.9 加入eCharts 2020.4.8 完成article的显示,其间碰到全局路由守卫写的有错误,导致跳转报错.已修复. 加入keep-alive功能,缓存视图数据 疑问:如果在全局组 ...
- Go语言系列之日志库zap
在许多Go语言项目中,我们需要一个好的日志记录器能够提供下面这些功能: 能够将事件记录到文件中,而不是应用程序控制台. 日志切割-能够根据文件大小.时间或间隔等来切割日志文件. 支持不同的日志级别.例 ...
- Spark案例练习-PV的统计
关注公众号:分享电脑学习回复"百度云盘" 可以免费获取所有学习文档的代码(不定期更新) 云盘目录说明: tools目录是安装包res 目录是每一个课件对应的代码和资源等doc ...
- PPT2010制作清明上河图动画
原文: https://www.toutiao.com/i6492312556915393038/ 新建一个空白幻灯片 选择"插入"选项卡,"图像"功能组,&q ...
- Web开发之Servlet
当一个请求到达服务端,服务器怎么处理? 当一个请求到达服务端时,由服务端的引擎来进行分析.它根据工程名找到工程, 然后拿到URL的资源地址和web.XML文件的所有的进行对比,和哪一个对比上就找到了具 ...
- 🏆【Alibaba中间件技术系列】「RocketMQ技术专题」Broker服务端自动创建topic的原理分析和问题要点指南
前提背景 使用RocketMQ进行发消息时,一般我们是必须要指定topic,此外topic必须要提前建立,但是topic的创建(自动或者手动方式)的设置有一个开关autoCreateTopicEnab ...
- 【记录一个问题】opencv中使用UMat类,在析构的时候出现refcount == 0的断言错误
发生coredump时的错误信息如下: terminate called after throwing an instance of 'cv::Exception' what(): OpenCV(4. ...
- golang中的标准库数据格式
数据格式介绍 是系统中数据交互不可缺少的内容 这里主要介绍JSON.XML.MSGPack JSON json是完全独立于语言的文本格式,是k-v的形式 name:zs 应用场景:前后端交互,系统间数 ...
- gorm声明模型
模型定义 模型是标准的结构体,由go的基本数据类型.实现了Scanner和Valuer接口的自定义类型及其指针或别名组成 例如: type User struct { ID uint Name str ...