首页 > 其他分享 >P10851 [EGOI2024] Make Them Meet / 活动面基

P10851 [EGOI2024] Make Them Meet / 活动面基

时间:2024-10-15 20:33:02浏览次数:1  
标签:Them fa dep Make vis dfs EGOI2024 int 同色

构造题做的太少了,感觉这题是非常厉害的构造题。

考虑菊花图。菊花图结构非常简单,我的做法是先让所有点颜色相同,这样如果两个人分别在叶子上就可以在根相遇,否则一定会有一人走到根上,再与叶子挨个匹配即可。

考虑链的做法。我们可以考虑把两个人往中间赶,他们肯定可以相遇。但是这种想法非常不好构造方案,想想有没有别的方法?转换思路,我们很难把人往中间赶,但是我们可以将他们都往同一方向走,到边上就会反弹,这样也能让他们相遇。

具体的,对于每一轮,奇数轮 \((1,2)\) 同色,\((3,4)\) 同色......偶数轮 \((2,3)\) 同色,\((4,5)\) 同色以此类推即可。我们发现两人都会往同一方向走。完全图也可以用这种方法。

然后考虑树的做法。有了链的方法,树的构造方法也可以很自然的想到。我们按深度奇偶性染色,向刚刚一样。我们还需对于树根 \(rt\) 找到一个儿子 \(son\),在每一轮都与根颜色相同,这样可以让达到根的人在 \(rt\) 和 \(son\) 之间来回走。

现在考虑将树的构造套到一般图上。

理清思路,考虑一般图要有哪些性质才能使用树的构造方法?

  1. 对于任意节点 \(u\),\(u\) 的任意两个儿子之间不能连边。
  2. 对于根节点 \(rt\),\(rt\) 不能与选出的 \(son\) 的任意儿子连边。

实际上是要寻找一个合法的生成树,显然按 dfs 序生成的树是可以完美的满足性质一的,如果跑出来的是一条链,则可以直接用链的构造方法。否则,我们要找到根,使得根满足性质二。

我们找到一个按 dfs 序生成的树的分叉点,使得该点子树内没有其它分叉点(即这个点下挂有若干条链)。直接找最深的就行。为什么要找到最深的?因为在接下来的步骤中会有不好处理的地方,之后会讲。

设这个点为 \(q\),其父亲为 \(p\),如果存在一个 \(q\) 的儿子 \(u\) 与 \(p\) 不连边,那么我们很幸运地找到了一个可行的根。我们可以将 \(u\) 设为根,并将其在原树下挂的链暂时删去,然后先从 \(u\) 走到 \(q\),再走完 \(q\) 原来的儿子,最后再走到 \(p\) 进行生成树的构造。生成完后将删去的链再挂回来即可。容易发现这样生成出来的树,树根是可以满足性质二的,选出的 \(son\) 即为 \(q\)。

如果 \(q\) 的所有儿子与 \(p\) 之间都有边,没关系,我们随便找一个 \(u\),作为新的根,dfs 构造树的时候先到 \(q\) 中的儿子进行搜索,由于 \(q\) 中的每个儿子与 \(p\) 都有连边,那么在新的树中 \(p\) 可以作为一个 \(q\) 的儿子的儿子,这样生成出来的树也能满足性质二。

生成完后怎么做?这就体现出找最深的分叉点的优越性了。我们注意到生成出来的树的根节点只有两个儿子,并且子树分别为一棵正常的树和一条链。我们采取一般性的方法,奇数轮让深度为 \(2,4,\cdots\) 的点与父亲同色,偶数论让深度为 \(3,5,\cdots\) 的点与父亲同色,为什么不让深度为 \(1\) 的点连向根?因为细心的你可以发现,我们无法保证根的两个儿子之间不存在边。那么我们考虑每次新增加一轮,在偶数轮之前,将链的顶与根这两个点同色。然后在原来的奇偶轮中,保证根 \(u\) 与 \(q\) 同色。

这样构造可以发现,若一个人在子树中,他上去会在 \(u\) 与 \(q\) 徘徊。而如果一个人在链中,他将会在 \(q\) 时有两条路走,一条是走到子树中,然后上来并在 \(u\) 与 \(q\) 徘徊。另一条是回到链,并在 \(q\) 到链底往返走。

来分析一下最劣情况,应该是两个人都在链中,其中一个先到根部然后进入子树,而另一个人则走回链底,他们刚好错开了。这样如果是最劣的话,设链的长度为 \(l\),那么经过的路径长度大概为 \(3l\),操作次数则为 \(3l\times 1.5=4.5l\),则操作次数复杂度为 \(\mathcal{O}(4.5n)\)。

终于做完啦!

代码:

#include <bits/stdc++.h>
#define rep(i, l, r) for (int i = l; i <= r; ++ i)
#define rrp(i, l, r) for (int i = r; i >= l; -- i)
#define pii pair <int, int>
#define eb emplace_back
#define id(x, y) n * ((x) - 1) + (y)
#define ls p << 1
#define rs ls | 1
#define MN 1000000000000000000
using namespace std;
using namespace __gnu_cxx;
constexpr int N = 100 + 5, P = 1e9;
constexpr double PI = acos (-1.0);
inline int rd () {
  int x = 0, f = 1;
  char ch = getchar ();
  while (! isdigit (ch)) {
    if (ch == '-') f = -1;
    ch = getchar ();
  }
  while (isdigit (ch)) {
    x = (x << 1) + (x << 3) + ch - 48;
    ch = getchar ();
  }
  return x * f;
}
int n, m;
int col[N];
bool e[N][N], vis[N];
void init () {
  rep (i, 1, n) col[i] = i;
}
void put () {
  rep (i, 1, n) printf ("%d ", col[i]);
  puts ("");
}
int id[N], tot;
vector <int> t[N], G[N];
int dep[N], fa[N];
void dfs (int u) {
  vis[u] = 1; id[++ tot] = u;
  for (auto v : G[u]) {
    if (vis[v]) continue;
    dep[v] = dep[u] + 1; fa[v] = u; dfs (v);
  }
  rep (v, 1, n) {
    if (! e[u][v] || vis[v]) continue;
    dep[v] = dep[u] + 1; fa[v] = u; dfs (v);
  }
}
int main () {
  // freopen ("1.in", "r", stdin);
  // freopen ("1.out", "w", stdout);
  dep[0] = -1;
  n = rd (), m = rd ();
  int T = 420;
  rep (i, 1, m) {
    int u = rd () + 1, v = rd () + 1;
    e[u][v] = e[v][u] = 1;
  } dfs (1);
  rep (i, 1, n) t[fa[i]].eb (i);
  bool chk = 1;
  rep (i, 1, n) {
    if (t[i].size () > 1) chk = 0;
  }
  if (chk) {
    cout << T << endl;
    rrp (i, 1, T) {
      init ();
      rep (j, 2, n) {
        if ((dep[id[j]] & 1) == (i & 1)) col[id[j]] = col[fa[id[j]]];
      }
      put ();
    } return 0;
  }
  int q = 0, p = 0;
  rep (i, 1, n) {
    if (t[i].size () > 1) {
      if (dep[q] < dep[i]) q = i, p = fa[i];
    }
  }
  int u = t[q][0];
  for (auto v : t[q]) if (! e[v][p]) u = v;
  memset (vis, 0, sizeof vis);
  if (! t[u].empty ()) {
    int v = u;
    while (! t[v].empty ()) v = t[v][0], vis[v] = 1;
  }
  G[u].eb (q);
  G[q] = t[q];
  if (p) G[q].eb (p);
  tot = 0; fa[u] = 0;
  dep[u] = 0; dfs (u);
  if (! t[u].empty ()) {
    int v = u;
    while (! t[v].empty ()) dep[t[v][0]] = dep[v] + 1, v = t[v][0], id[++ tot] = v;
  }
  cout << T << endl;
  rrp (i, 1, T) {
    init ();
    if ((i % 3) <= 1) col[q] = col[u];
    rep (j, 3, n) {
      if (((fa[id[j]] == u) ? 2 : (dep[id[j]] & 1)) == (i % 3)) col[id[j]] = col[fa[id[j]]];
    }
    put ();
  }
  return 0;
}

标签:Them,fa,dep,Make,vis,dfs,EGOI2024,int,同色
From: https://www.cnblogs.com/lalaouyehome/p/18468378

相关文章

  • Makefile
    Makefile是由target和命令构成的,最简单的Makefile:build: gcctest.c-otest然后执行makebuild就会执行gcc这条命令,但是一般推荐先将源文件构建为对象文件,然后再统一编译为可执行文件build:test.o gcctest.o-otesttest.o: gcctest.c-c文件目标test.o是build伪......
  • Swift中Themeable
    在Swift中,Themeable协议通常用于创建可以根据主题变化而改变外观的对象,比如UI组件、视图控制器等。通过实现这个协议,你可以为你的应用提供主题切换的功能,使其在不同的视觉风格下仍然保持一致性。定义Themeable协议一个简单的Themeable协议可能如下所示:protocolThemea......
  • cmake使用方法
    CMake是一个跨平台的构建系统生成器,广泛用于C++项目。它允许开发者编写平台无关的构建脚本(称为`CMakeLists.txt`),然后在不同的平台上生成对应的构建文件(如Makefile、VisualStudio项目文件等)。以下是使用CMake的基本步骤和一些常见的用法。 ###安装CMake首先,你需......
  • windows下基于cmake配置opencv并使用visual studio编译
     在Windows上下载并编译OpenCV,然后配置系统环境变量的步骤如下:1.下载OpenCV打开OpenCV官方下载页面。找到最新的Windows版本,点击下载,例如:opencv-4.x.x-vc14_vc15.exe,这将是一个自解压文件。下载完成后,双击opencv-4.x.x-vc14_vc15.exe文件,选择一个目录将其解压,......
  • 简单的cmake使用
    使用CMakeLists.txt生成可执行文件编写一个最简单的CMakeLists以生成可执行文件,仅需要以下三步指明最小支持的cmake版本cmake_minimum_required指明项目的代号或者说名称project使用add_executable来生成可执行文件其中add_executable参数为可执行文件名称,后面跟着源文......
  • cmake使用笔记
    cmake_cxx_flags常用值在CMake中,CMAKE_CXX_FLAGS是一个用于指定C++编译器选项的变量。你可以将不同的编译选项添加到这个变量中,以影响编译过程的行为。以下是一些常用的CMAKE_CXX_FLAGS值及其说明:1.优化选项1.-O0:禁用优化(默认选项)。2.-O1:启用一级优化。3.-O2:启用二......
  • cmakelist 源码生成so 文件 orthanc mysql
    cmakelist.txt#Orthanc-ALightweight,RESTfulDICOMStore#Copyright(C)2012-2016SebastienJodogne,MedicalPhysics#Department,UniversityHospitalofLiege,Belgium#Copyright(C)2017-2023OsimisS.A.,Belgium#Copyright(C)2024-2024Orthanc......
  • [ABC227H] Eat Them All 题解
    唐唐题。思路容易发现,我们只要知道了一条边总共经过了多少次(不计方向),我们就可以跑欧拉回路。自己手玩一下,发现只要枚举四个变量,其他的都可以用方程解出来。求完之后,还需要判一下联通性。实际效率是很快的,远远跑不满。时间复杂度:\(O(a_i^4)\)。Code#include<bits/stdc++.h......
  • CMake 属性之目录属性
    【写在前面】CMake的目录属性是指在特定目录(及其子目录)范围内有效的设置。这些属性不同于全局变量或目标(Target)属性,它们提供了一种机制,允许开发者为项目中的不同部分定义不同的构建行为。通过目录属性,你可以指定编译器选项、包含路径、预处理定义等,而无需在每个目标或文件中重......
  • CMake 属性之目录属性
     【写在前面】        CMake的目录属性是指在特定目录(及其子目录)范围内有效的设置。        这些属性不同于全局变量或目标(Target)属性,它们提供了一种机制,允许开发者为项目中的不同部分定义不同的构建行为。        通过目录属性,你可以指定编译器......