【NOI省选 2023】总结
D1T1 火车站
题意:这是一道签到题。有 \(n\) 哥点和一个火车,以及 \(m\) 个轨道,第 \(i\) 个轨道覆盖 \([l_i,r_i]\)。一开始火车在任意一条 \(l_i\le x\le r_i\) 的轨道的点 \(x\) 处,以及一个方向(左右,自行分类讨论),火车在中途不能改变方向。火车每到达一个点,可以切换到包含这个点的任意一条轨道。当火车处于一条轨道的尽头时,其停止。求火车最后可能停止在哪些点。\(1\le n,m\le 2\times10^5\)
显然,这是一道签到题。
左右分类讨论,钦定火车往左走。那么选择若干条可以覆盖 \(x\) 并往左延伸的轨道,这些轨道的 \(l_i\) 即为答案。时间复杂度 \(O(n)\)。
D1T2 城市建造
题意:一张连通图,\(n\) 个点 \(m\) 条边。选若干个数量 \(>1\) 的点,断掉这些点两两之间的所有边,满足每个点各属于一个连通块,并且连通块的大小极差 \(\le k\),求方案数 \(\bmod 998244353\)。\(1\le n\le 10^5,\space n-1\le m\le 2\times 10^5,\space 0\le k\le 1\)
考虑 \(k=0\) 时怎么做。
不难发现,如果选择了两个点,那么这两个点之间的所有路径上的点都要选。进一步的,如果一个点双中选择了两个点,那么整个点双都要选,并且最后选的点形成一个连通块。
考虑先用广义圆方树缩点,转成一棵树。考虑这棵树的重心 \(rt\),不难证明,\(rt\) 一定会被选,于是只需要把 \(rt\) 作为树根即可。
考虑枚举连通块大小 \(b\),一共有 \(O(\sqrt n)\) 个。对于每个 \(b\),跑一次树形 \(\text{DP}\)。
设 \(f[u]\) 表示选择 \(u\),并且考虑了 \(u\) 的子树的选择方案数(当 \(k=0\) 时,\(f[u]\) 只可能等于 \(0,1\))。
分类讨论。若 \(u\) 为方点,显然,\(f[u]=\prod \limits_{v\in \text{son}(u)} f[v]\),即等于所有儿子圆点的值。
若 \(u\) 为圆点,设子树大小为 \(siz[u]\),分类讨论:
-
\(siz[u]<b\):此时 \(u\) 一定不选(如果选,那么父亲不能选,与“最后选的点形成一个连通块”或“数量 \(>1\) ”矛盾),令 \(f[u]=0\)。
-
\(siz[u]=b\):此时 \(u\) 选择后,\(u\) 子树形成一个连通块,\(f[u]=1\)。
-
\(siz[u]>b\):那么 \(u\) 选择,设 \(sum\) 表示 \(u\) 所在联通款大小,初始时 \(sum=1\)。对于每个儿子 \(v\),若 \(siz[v]<b\),那么 \(v\) 及其子树都包含在 \(u\) 连通块中,\(f[u]\) 不变,\(sum\leftarrow sum+siz[v]\);若 \(siz[v]\ge b\),说明 \(v\) 被选择,\(u\) 和 \(v\) 不在同一个连通块中,\(f[u]\leftarrow f[u]\times f[v]\)。最后,\(f[u]\leftarrow f[u]\times [sum=b]\)。
当 \(k=1\) 时
枚举最小的连通块大小 \(b\),判断合法性,不难发现,\(b\) 最多 \(O(\sqrt n)\) 个。
\(\text{DP}\) 时,方点处理方法相同,对于圆点:
-
圆点 \(u\) 和其儿子 \(v\) 若 \(siz[v]=b\):若 \(f[v]>0\),说明 \(v\) 选不选都行,令 \(cnt\) 表示这样的儿子的个数,那么 \(cnt\leftarrow cnt+1\);若 \(f[v]=0\),\(v\) 一定不选,令 \(sum\leftarrow sum+siz[v]\)。
-
\(siz[v]\) 处于其他情况时,与圆点处理方法相同。
-
最后,有两种方法:\(u\) 连通块不包含 \(siz[v]=b\) 的点 \(v\),那么贡献为 \(f[u]\times [b\le sum\le b+1]\);\(u\) 连通块包含一个(不难发现至多包含一个)\(siz[v]=b\) 的点 \(v\),贡献为 \(f[u]\times [sum=1]\times cnt\)。最终的 \(f[u]\) 即为两种贡献的和。
D1T3 人员调度
D2T1 过河卒
考场代码被卡常,痛失 \(50pts\)。
注意到 \(n,m\le 10\),考虑一种暴力状态:\((rx_1,ry_1,rx_2,ry_2,bx,by,0/1)\),分别表示三个棋子的位置状态。建立图论模型,每个状态是一个点,点与点之间建立有向边。不难发现,这是一个有环的有向图,不能直接拓扑排序。
这是一个非常特殊的拓扑排序,设 \(win[u]\) 表示点 \(u\) 的胜负状态,\(win[u]=-1\) 表示还未确定,\(win[u]=1/0\) 表示胜/负,设 \(f[u]\) 表示步数。
从终止状态开始拓扑排序,分两个队列 \(q_0,q_1\),存储 \(win[u]=0\) 的点以及 \(win[u]=1\) 的点。
设当前取出点 \(u\)。若 \(q_0\) 不为空,则令 \(u\) 为 \(q_0\) 队头,否则为 \(q_1\) 队头。
枚举每个有边的点 \(v\),若 \(win[u]=0\),那么 \(win[v]=1\),更新 \(f[v]\leftarrow \min(f[v],f[u]+1)\),若 \(v\) 未进入过队列,则把 \(v\) 放进 \(q_1\)。
若 \(win[u]=1\),我们只能更新 \(win[v]=-1\) 的点。维护 \(out[v]\) 表示 \(v\) 还有多少个胜负状态未知的点,那么更新 \(out[v]\leftarrow out[v]-1,f[v]=\max(f[v],f[u]+1)\),若 \(out[v]=0\),那么把 \(v\) 加入 \(q_0\)。
时间复杂度 \(O(Tn^3m^3)\),需卡常。
D2T2 填数游戏
题意:两个人 \(\text{A,B}\),有 \(2n\) 个大小在 \([1,2]\) 之间且值域在 \([1.m]\) 之间的集合 \(S_{1...n},T_{1...n}\),\(\text{A}\) 先从 \(S_{1...n}\) 中各选一个数,然后 \(\text{B}\) 在得知 \(\text{A}\) 选的数后从 \(T_{1...n}\) 中各选一个数,并且 \(\text{B}\) 选的数互不相同。设 \(X\) 为有多少个位置满足对应的两个数相同,\(\text{A}\) 想最大化 \(X\),\(\text{B}\) 想最小化 \(X\),求最终的 \(X\)。\(1\le n,m\le 1.5\times 10^6\)
考虑图论模型。从 \(\text{B}\) 的选择出发,对于 \(T_i\) 中的两个数(若只有一个,则把这个数复制),把这两个数在值域上连边。不难发现,若存在一个连通块 \((V,E)\) 满足 \(|E|>|V|\),则无解。
那么一个连通块只有可能 \(|E|=|V|\) 或 \(|E|=|V|-1\)。
先看 \(|E|=|V|\),此时是一个基环树。对于环上边,\(\text{B}\) 可以有顺时针和逆时针两种选法;对于树上边,只能选向叶子的那个点。先统计出树上边的贡献,对于环上的一条边,有三种类别:
-
一类边:该边对应 \(T_i\) 满足 \(S_i=T_i\),此时 \(\text{A}\) 可以选这条边的左端或右端。
-
二类边:对应的 \(T_i\) 与 \(S_i\) 恰好有一个数相同,此时 \(\text{A}\) 必定选那个相同的数。
-
三类边:对应的 \(T_i\) 与 \(S_i\) 无交集,此时没有贡献。
设 \(c,c_1,c_2\) 分别表示环上一类边数量、二类边中顺时针选有贡献的边数量、二类边中逆时针选有贡献的边数量。
不难发现,环上的贡献为 \(\min(c_1+c,c_2+c,\lfloor\frac {c_1+c_2+c} 2\rfloor)\)。
对于 \(|E|=|V|-1\),此时是一棵树。对于 \(\text{B}\),存在一个不选的数。若确定了这个不选的数,那么其实所有边选哪一端都能确定。
设这个不选的数为 \(x\),如果没有一类边,很好处理:设 \(cost[x]\) 表示不选 \(x\) 时的贡献,那么一棵树内所有点的 \(cost\) 容易换根处理。最后整棵树最小的 \(cost\) 即为贡献。
若有一类边,对于每一条一类边,发现 \(\text{A}\) 要么给这条边的子树的 \(cost\) 全部 \(+1\),要么给子树外的所有点的 \(cost\) 全部 \(+1\),\(\text{A}\) 要使得所有点的 \(cost\) 的最小值最大化。
不难发现,若存在树上位置并列(即没有祖孙关系)的两条一类边,他们不可能同时给各自的子树 \(+1\),因为他们全部给子树外 \(+1\) 时,不仅各自的子树都被对方 \(+1\),而且两个子树外的点都被 \(+2\),这样更优。
因此,对子树 \(+1\) 的一类边只可能出现在一条链上。
考虑一种常用思想:调整法。先令所有一类边向子树外 \(+1\),然后调整一些边。具体的,从任意一点为根开始 \(\text{DFS}\)。设 \(u\) 为当前点,维护每个点的子树内最小的 \(cost\),设为 \(minc\)。若 \(cost[u]=minc[u]\),我们无法通过调整 \(u\) 子树内的边来增大 \(cost[u]\),直接退出。否则,求出当前所有儿子 \(v\) 中的 \(minc[v]\) 的最小值 \(mn\) 和次小值 \(se\),维护当前最多能让最小的 \(cost\) 加多少,设为 \(k\),那么 \(k\leftarrow \min(k,\lfloor\frac{\min(se,cost[u])-mn}2\rfloor)\),继续 \(\text{DFS}\) 即可。