JOISC2020 划水记&题解(施工中)
\(Part1\) 游记
咕咕咕
\(Part2\) \(solutions\)
不会的/没写完的先鸽着,补题之后再补
目前只写了 \(D1T1\) \(D2T2\) \(D3T3\) \(D4T1\)
\(solutions\) \(for\) \(Day1\)
\(D1T1\)
$description : $ LOJ链接
$solution : $
首先有一个\(O(n^2)\)的朴素\(dp:\)
记 \(f[i][j][0/1]\)表示考虑到前\(i+j\)个数\(,\)选了\(i\)个\(A\)和\(j\)个\(B,\)第\(i+j\)个数选的是\(A/B,\)是否可行\(.\)
这个\(dp\)的期望得分是\(12\)分\(.\)
一种想法
一种想法是考虑构造出一个合法的方案\(.\)
记 \(f[i][0/1][0/1]\) 表示在考虑序列的前\(i\)个\(,\)第\(i\)个选的是\(A/B,\)最多的\(A/B\)的数量是多少\(.\)
考虑从尾到头构造方案\(.\) 对每个位置枚举这个位置用\(A\)还是用\(B,\)
记当前位置为 \(now,\) 当前位置的字符为 \(c,\) 已经用了 \(cntA\) 个 \(A\) 和 \(cntB\) 个 \(B.\)
那么方案合法的条件就是 \(cntA\) \(+\) \(f[now][c][0] \geq n\) 且 \(cntB + f[now][c][0] \geq n.\)
按这种方法构造方案即可 \(.\) 复杂度 \(O(n).\)
"一种想法"的正确性证明\(:\) \((by\) \(czynt\) \()\)
如果存在 \(max({a_i,b_i})>max({a_{i+1},b_{i+1})}\)或者\(min({a_i,b_i}) < min({a_{i+1},b_{i+1}}),\)就没得选择\(,\)不用考虑他\(.\)
现在考虑\(,\)如果\(max({a_i,b_i}) \leq min({a_{i+1},b_{i+1}}),\)那就是分开的\(;\)
你用这个可以把它分成若干段\(;\)
现在问题就是每一段里面可不可以任意分\(.\)
我们发现你可以在任意时候跳到比较高的上面去\(,\)就行了\(.\)
\(D1T2\)
$description : $ LOJ链接
$solution : $
一种乱搞
把所有的矩形 cpp random_shuffle()
一下\(,\)然后把前\(k\)个矩形找出来作为起始矩形\(,\)后面的\(n-k\)个矩形用贪心的方法决策和\(k\)个矩形中的哪一个求交\(.\)
这个做法可以过掉赛时的数据\(.\) 然而赛后\(uoj\)上就被\(hack\)了
\(solutions\) \(for\) \(Day2\)
\(D2T2\)
$description : $ LOJ链接
$solution : $
显然题意相当于我们可以一边加入边\((A_i,B_i)\)一边进行题目中的操作\(.\)
我们把同时存在边\((u,v)\)和\((v,u)\)的点对合并起来\(,\)缩成一个块\(.\)
那么一条两个块之间的边\((cur_x,cur_y)\)对答案的贡献为\(size_{cur_y}\)
一个大小为\(s\)的联通块对答案的贡献为\(s*(s-1)\)
在联通块之间出现可合并的点对时合并联通块\(,\)并把某一个联通块的所有边都合并到另一个联通块上\(.\)
可以用启发式合并解决\(.\)复杂度\(O(mlog^2m)\)
\(solutions\) \(for\) \(Day3\)
\(D3T3\)
$description : $ UOJ链接
$solution : $
这题可以分为两个不同的子任务\(:\)一是\(A=3,B=0,m>=n-1,\)另一个是\(A=2,B=6,m=n-1\)
\(case1:\) \(A=3,B=0,m>=n-1\)
这个子任务的含义\(,\)就是说我有三种标记\(,\)在任意图的情况下每一步都必须沿着最短路走\(.\)
以下为了方便\(,\)把标记看成颜色\(,\)不同的标记即不同的颜色\(.\)
我们考虑以终点\(0\)为根对给定的图进行\(BFS.\)记\(dis_i\)为\(0->i\)的最短路\(.\)
\(BFS\)之后\(,\)对于图中的一条边 $ (u,v) $ 一定有 \(|dis_u-dis_v] \leq 1\)
换言之\(,\)我们\(BFS\)后的图就是有若干"层"点\((\) 我们把\(dis_x\)相同的点看做一层 \(),\)其中层与层之间有连边\(,\)同时一层点的内部也有相互连边\(.\)
那么我们需要保证\(,\)对于每个点我们必须能够让它能判断下一步往哪个标记走\(,\)
并且保证下一步一定走向下一层点\(,(\)即\(dis_x\)更小的点\(,\)也就是说\(,\)不能走到\(dis\)更大的点\(,\)也不能通过这一层内部的边走到\(dis\)相同的点\().\)
所以我们就可以知道\(:\)
\(1.\)每一层的点与下一层的所有连边应该是同种颜色\(;\)
\(2.\)每一层内部的连边的颜色应当和前一层连接到这一层的边颜色相同\(.\)
最后还剩下一个问题\(:\)对于一个点\(,\)
我可能会在int Move(vector<int> y)
中\(get\)到两种可能的颜色\(,\)但我要怎么\(check\)哪一种颜色是我这一步需要走的呢\(?\)
有一个(可能)比较精妙的构造 \(:\) 我们可以给颜色设计一个类似石头剪刀布的优先级 \((\) 比如 \(,\) \(0>1,1>2,2>0\) \().\)
这样我们就可以解决这个\(case\)了\(.\)
关键代码\(:\)
//Anthony 比较长,就不贴了,评测链接里有代码
//Catherine
namespace subtask0{
int A,B;
int work(std::vector<int>y){
int i,s = 0,a = -1,b = -1;
for (i = 0; i < A; ++i) if (y[i]){ if (a == -1) a = i; else b = i; }
if (b == -1) return a;
//这里的a和b是和当前点相邻的边的两种颜色
if (a > b) swap(a,b);
if (!a && b == 1) return 0;
if (a == 1 && b == 2) return 1;
if (!a && b == 2) return 2;
}
}
\(case2\) \(:\) \(A=2,B=6,m=n-1\)
这个子任务呢\(,\)就是要求我们给一棵以 \(0\) 为根的树上黑白染色\(,\)然后通过不超过 \(dis+6\) 步能成功走到点 \(0\) \(.\)
由于是一棵树\(,\)所以对于一个节点\(x,\) \(x\)的父节点只有一个\(,\)而子节点可以有一个或多个\(.\)
如果说一个点的 \(u\) 度数 \(>2\) \((\) 换言之 \(,\) \(u\) 有不止一个子节点 \(),\)
那么我们就必须 把 \(u\) 与儿子之间的所有边 设成同一个颜色 \(,\) 且和 $ $ \(u\) 与父亲之间的边 颜色不同 \(.\)
这样的话\(,\)当我走到的点\(degree>=3\) 或 \(degree = 1\) 时 \(,\)我就能够简单的判断方向 \(,\) 知道下一步应该走哪里 \(.\)
问题来了 \(!\) 如果有一条直上直下的长链\(,\)链上所有点的度数都是 \(2,\) 怎么办啊 \(?\)
因为度数为 \(2,\) 而根据上述的连边方式是不能在 \(6\)次错误之内 判断方向的\(,\)所以我们要对现有的方案进行一些修改 \(.\)
具体来说\(,\)我们是要对链进行一些修改\(,\)使得在链上可以快速判断方向\(.\)
通过一些人类智慧\(,\)我们有了一个字符串\(010011.\)
这个字符串有着很好的性质\(:\)我们一旦\(get\)到了他的一个循环同构串\(,\)就可以直接判断是正向还是反向\(.\)
这个字符串怎么用呢\(……\)
我们把这个串的循环挂在链上 \(,\) 如 \(010011010011...\) 或 \(100110100110...\)
因为\(B=6\) \(,\) 所以我们只能向错误的方向最多走 \(3\) 步 \(.\)
但是我们发现走了三步之后正好能\(get\)到串的 \(5\) 个字符 \(,\) 那么这个串的一个循环同构串也就被唯一确定了 \(.\)
至此我们能够在 \(3\) 步之内正确判断一条链上的方向 \(.\) 如果中途碰到度数 \(= 1\) \(or\) \(\geq 3\) 的点我们就可以直接\(check\)了 \(.\)
那么这个 \(case\) 也被我们解决了 \(.\)
//这个case代码量较大,不适合贴在博客里,但是评测链接里有代码
\(solutions\) \(for\) \(Day4\)
\(D4T1\)
$description : $ 目前只有\(atcoder\)上有\(,\) \(loj/uoj\) 上都没有 \(,\) 就不挂链接了
$solution : $
一种十分暴力但是非常难写的做法
我们考虑对于每种颜色强行求出如果要包含它\(,\)需要的颜色种类有多少种\(.\)
对每种颜色建出虚树\(.\)然后如果颜色\(c\)包含了虚树上的一个点\(,\)那么就向那个点所在的颜色连边\(.\)
最后\(,\)如果颜色\(u\)在图上能走到另一个颜色\(v,\)说明颜色\(u\)需要包含的颜色集合中有\(v.\) 那么我们只要求出缩点之后的图就可以解决问题了\(.\)
现在我们有\(O(n)\)个 一个点 往 树上的一条链 连边的操作\(.\)考虑优化建图\(.\)
树剖\(,\) \(st\) 表优化建图 \(,\) 最后 \(tarjan\) 缩点解决\(.\)
时空复杂度为\(O(nlogn),\)代码长度很长 \((\) \(5\) 个 \(K\) \()\) \(,\) 空间很紧\(.\)
一种简易方便的做法
咕咕咕