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\)

LOJ评测链接 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\) \()\) \(,\) 空间很紧\(.\)

评测链接1(空间500MB)

评测链接2(空间487MB)


一种简易方便的做法

咕咕咕

posted @ 2020-08-29 10:39  srf  阅读(272)  评论(0编辑  收藏  举报