\(\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::vectorsize() 为 \(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」迷路的猫的更多相关文章

  1. 「JOISC 2020 Day2」变态龙之色 题解

    题目传送门 注意 同性必定不同色 必有一个同色异性,且不相互不喜欢 Solution 我们发现,我们问题比较大的就是如何确定性别问题.我们可以一个一个加进去,在原来已经确定了的二分图上增加新的性别关系 ...

  2. 「JOISC 2020 Day1」汉堡肉

    我终于学会打开机房的LOJ了! description LOJ3272 有\(n(n<=2*10^5)\)个矩形,让你找\(k(k<=4)\)个点可以覆盖所有矩形(点可重复),输出一种方案 ...

  3. 「JOISC 2020 Day4」首都城市

    题目   点这里看题目. 分析   做法比较容易看出来.我们对于每个城市,找出那些 " 如果这个城市在首都内,则必须在首都内的其它城市 " ,也就是为了让这个城市的小镇连通而必须选 ...

  4. 「JOISC 2014 Day1」 历史研究

    「JOISC 2014 Day1」 历史研究 Solution 子任务2 暴力,用\(cnt\)记录每种权值出现次数. 子任务3 这不是一个尺取吗... 然后用multiset维护当前的区间,动态加, ...

  5. Loj #2731 「JOISC 2016 Day 1」棋盘游戏

    Loj 2731 「JOISC 2016 Day 1」棋盘游戏 JOI 君有一个棋盘,棋盘上有 \(N\) 行 \(3\) 列 的格子.JOI 君有若干棋子,并想用它们来玩一个游戏.初始状态棋盘上至少 ...

  6. 「JOISC 2019 Day3」穿越时空 Bitaro

    「JOISC 2019 Day3」穿越时空 Bitaro 题解: ​ 不会处理时间流逝,我去看了一眼题解的图,最重要的转换就是把(X,Y)改成(X,Y-X)这样就不会斜着走了. ​ 问题变成二维平面上 ...

  7. 【LOJ】#3036. 「JOISC 2019 Day3」指定城市

    LOJ#3036. 「JOISC 2019 Day3」指定城市 一个点的可以dp出来 两个点也可以dp出来 后面的就是在两个点的情况下选一条最长的链加进去,用线段树维护即可 #include < ...

  8. 【LOJ】#3034. 「JOISC 2019 Day2」两道料理

    LOJ#3034. 「JOISC 2019 Day2」两道料理 找出最大的\(y_{i}\)使得\(sumA_{i} + sumB_{y_i} \leq S_{i}\) 和最大的\(x_{j}\)使得 ...

  9. 【LOJ】#3032. 「JOISC 2019 Day1」馕

    LOJ#3032. 「JOISC 2019 Day1」馕 处理出每个人把馕切成N段,每一段快乐度相同,我们选择第一个排在最前的人分给他的第一段,然后再在未选取的的人中选一个第二个排在最前的切一下,并把 ...

随机推荐

  1. [ SQLAlchemy ] 关于dynamic的“一知半解”

    问题提出: 1.粉丝机制 2.评论的点赞功能 这两个功能分别由User类和Comment类来实现,同样定义了多对多的关系,查询的时候用的方法却大不一样,先看看代码吧. ### # User类的中间表 ...

  2. JS 利用新浪接口通过IP地址获取当前所在城市

    <html xmlns="http://www.w3.org/1999/xhtml"><head runat="server">< ...

  3. Go语言系列之标准库ioutil

    ioutil标准库中提供了一些常用.方便的IO操作函数 一.相关方法 func ReadAll(r io.Reader) ([]byte, error) func ReadDir(dirname st ...

  4. Centos6.9虚拟机环境搭建

    原文链接:https://www.toutiao.com/i6481534700216123918/ 一.准备工具 VMware Workstation CentOS-6.9-x86_64-minim ...

  5. Elasticsearch安装与配置

    一.下载(华为云) https://mirrors.huaweicloud.com/elasticsearch/https://mirrors.huaweicloud.com/kibana/7.6.2 ...

  6. vue-json-editor可视化编辑器的介绍与应用

    vue-json-editor可视化编辑器 最近项目中有用到json编辑器,我选用了这款vue的编辑器,看起来也是比较简洁,接下来就具体介绍一下它,以及内部属性. 一.vue-json-editor的 ...

  7. 简述伪共享和缓存一致性MESI

    什么是伪共享 计算机系统中为了解决主内存与CPU运行速度的差距,在CPU与主内存之间添加了一级或者多级高速缓冲存储器(Cache),这个Cache一般是集成到CPU内部的,所以也叫 CPU Cache ...

  8. PAT 乙级 1003. 我要通过!(20) (C语言描述)

    "答案正确"是自动判题系统给出的最令人欢喜的回复.本题属于PAT的"答案正确"大派送 -- 只要读入的字符串满足下列条件,系统就输出"答案正确&quo ...

  9. 你管这叫代理模式(Proxy Pattern)

    代理模式   代理模式即给一个真实类提供一个代理类,该代理类代替真实类完成其功能,一般还可在代理类上添加一些真实类不具有的附加功能,通俗来讲代理模式就是我们生活中常见的中介,代理模式又可分为静态代理和 ...

  10. Linux下Julia安装

    1.找到官网,执行 wget https://julialang-s3.julialang.org/bin/linux/x64/1.4/julia-1.4.0-linux-x86_64.tar.gz ...