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)


一种简易方便的做法

咕咕咕

原文地址:https://www.cnblogs.com/s-r-f/p/13581270.html