COCI2021-2022 Contest1 题解

更好的阅读体验戳此进入

(建议您从上方链接进入我的个人网站查看此 Blog,在 Luogu 中图片会被墙掉,部分 Markdown 也会失效)

原题面链接

Luogu题面

T1 Ljeto

题意

给你 n 条信息,表示 ti 时刻 ai 击中 bi,得为 100,然后如果有十秒以内连续击中两次的额外加 50 分。

1ai,bi8,若 1ai,bi4 表示其为一队,若 5ai,bi8 表示其为二队,输出两队得分。

Examples

Input_1

3

10 1 6

20 1 7

21 8 1

Output_1

250 100

Input_2

3

10 2 5

15 2 6

25 2 5

Output_2

400 0

Input_3

2

10 5 2

11 6 3

Output_3

0 200

Solution

需要注意如果有十秒内连续三次击中,可以加两次 50 分而不是三次,即若两次间隔小于十秒但中间仍有一次击中不算加分。

另外需要注意的是在 Luogu 的翻译题面中并没有说明 ti 升序输入,如果非升序则需要先离线排序一下,但原版题面中有这样一句

The numbers ti are distinct and are ordered increasingly.

保证了升序输入且不会有相同。

upd - 已向 Luogu 提交翻译错误,题面现已被修改。

将这两点想明白之后这个题就真的是一道入门题了,考虑记录每个人上次击中的时间,直接根据题意模拟即可。

T2 Kamenčići

题面

一行 (n350) 个石头有红蓝两种颜色,AliceBob 轮流从一端取一个,对于每个人当手中有 K 个红色石子时则失败,保证会有人获胜,求出两人谁获胜。

输出在保证两人均采用最优策略的情况下,谁将会取胜。若 Alice 胜利输出 DA,反之输出 NE

Examples

Input_1

4 1

CCCP

Output_1

DA

Input_2

8 2

PCPPCCCC

Output_2

DA

Input_3

9 1

PPCPPCPPC

Output_3

NE

Solution

先说几个乱搞的做法:

首先观察发现似乎可以贪心,如果一边红色一边蓝色显然最优方案一定是取蓝色的。

对于两边都是红色或者都是蓝色,我有个别的贪心方案但是假掉了,题解里有一个贪心方案是尽量让对方更快碰到红色,也就是找到除头尾外,哪边红色石头更近,或者找哪个蓝色石头更远,按照这个思路似乎可以切掉这道题,不过我认为这个方案正确性并不显然,有可能只是运气好数据比较水。

(贪心+随机化可以过更多点,不过因为是捆测,最后似乎还会是 0pts

回到正解,石头个数 n 满足 n350,这个数据范围显然可以区间 DP。

可以考虑令 dp(l,r,k) 表示石子仅剩下 [l,r] 的区间,轮到的人已经拿走了 k 个红色石子(这里显然因为 Alice 先手,轮流拿顺序固定,所以不需要将谁拿石子单独设置一维),然后考虑状态转移,当从当前区间移除一个石子的时候,会变为 [l+1,r][l,r1],然后取石子的人就变成了另一个,这时区间的维度已经考虑好了,就需要考虑 k 如何计算。

显然对于整个区间的红色石子是由三部分构成:区间内红色 + Alice 取走的 + Bob 取走的。

考虑用前缀和维护每个区间内的红色石子,我们又已经知道当前这个人取走的数量,那么设转移后的 kk,那么就有:

k=sum(N)(sum(r)sum(l1))k

考虑到对手之间获胜状态相反,所以需要取反。考虑到两人均选择最优方式挑选,所以需要或运算。

于是就会有如下状态转移方程:

dp(l,r,k)=¬dp(l+1,r,k)¬dp(l,r1,k)

此时考虑到边界条件就可以得出最终方程:

dp(l,r,k)={falsek>Ktruek>K¬dp(l+1,r,k)¬dp(l,r1,k)otherwise

考虑到初始化较为复杂,可以考虑 dfs + 记忆化搜索。

Code

T3 Logičari

题面

对一个基环树进行染色,使每个点有且仅有一个,不包括自身的,与他相连的点被染色,求最少染色数(包括无解情况)。

n105

Examples

Input_1

4

1 2

2 3

3 4

4 1

Output_1

2

Input_2

3

1 2

2 3

3 1

Output_2

-1

Input_3

7

1 2

2 3

3 4

4 5

5 6

6 7

2 4

Output_3

4

Solution

思路

该说不说这题的细节是真的多,改了一下午才过了...

不过这题也挺套路,核心思路考虑把基环树拆开做树上 DP

观察题意,首先考虑如果是普通树上的染色问题,很套路的树上 DP 即可解决,而基环树与普通树的区别,也就是多了一条边,使“树”上有且仅有一个环,那么我们的思路也就是将他转化为普通的树上问题。

于是考虑找到环上的任意一个边并将其断开,然后枚举这两个点可能的状态,并在 DP 的时候随时考虑这两个点。

找环上边

一般有两种方法,一种是维护并查集,当新的边连接的两个节点,是同一颗子树上的时候,要找的就是这个边。

另一种方式更简便一些,DFS 遍历整个树,当访问到了非父亲节点,但曾经访问过的节点时便说明这个边是环上的边。

删边

如果用的并查集维护,直接记录下并不将这个边存到树里即可。

如果用的 DFS,那么可以考虑直接遍历找到点删除,或每次调用的时候都判断是否为删掉的这个边。

状态设计

考虑在普通的树形 DP 中考虑被分割的两个节点,这里定义为 root1root2

考虑令被染色为 true,未被染色为 false

dp(i,j,k,l,m) 表示当前计算到了 i 节点,其状态和其父亲状态分别为 j,k,两个根的状态分别为 l,m

因为每个点有且只有一个与之相连的节点会被染色,所以我们可以考虑先假设当前节点所有子节点都不染色,并计算求和,然后分别枚举其每一个子节点,计算如果将该子节点涂色最终需要涂多少点,并取最小值。

但是这题的最大难点我认为就是上面这些过程中合法性的判断,也就是细节的处理。

同时因为状态十分复杂,考虑用 DFS + 记忆化实现。

细节处理

首先我们需要考虑,哪些状态是不可能出现的:

  1. 遍历到某个根节点,但当前状态与根节点已经定下来的状态不同。
  2. 遍历到某个根节点,父亲节点已被染色,且两个根节点都被染色,导致其中某个根节点,考虑上被临时删除的边之后有两个相连的点被染色。

然后我们需要考虑,什么时候当前的节点的子节点都不能被染色:

  1. 父节点已经被染色,即当前节点已经有了一个节点与之相连且被染色。
  2. 当前节点到了某一个根节点,而另一个根节点已被染色,与 1 同理。

还有个很重要的点就是我们假设都不染色进行求和操作的时候会爆 int 所以需要在求和时需要开 long long

主函数

回到我们之前说的,要枚举两个根节点的状态,我们可以考虑令其从其中某个根节点开始遍历,显然会简便很多,显然一共可能有如下四种情况。

Code

T4 Set

题目背景

在知名游戏 SET 中,存在着一些数字、形状、颜色等不同的卡片,玩家的目标是确定一个存在的 triplet of cards(即卡片的三元组,也就是三张卡片构成的组合),使其符合特定的要求。 MarinJosip 很快就对这个游戏感到无趣,并对其进行了加强。

题目描述

在本题中,定义每张卡片代表着一个仅由 1,2,3 构成的长度为 k 的序列,共有 n 张卡片,卡片之间是无序的。

定义一个 SET 表示,当且仅当一个无序的 triplet of cards 其中的三个序列的每一位均相同或各不相同,用原文中的话就是 samepairwise different,更严谨地表示,我们令这三个序列为 Si,Sj,Sk,则一定满足如下条件:

  • i<j<k
  • x[1,k],满足 Si(x)=Sj(x)=Sk(x)Si(x)Sj(x)Sk(x)

例如 (1123,1322,1221) 便满足 1,3 位均相同,2,4 位各不相同。

给你这些序列,求可以组成多少种本质不同的 SET

输入格式

第一行为两个整数正整数 n,k

接下来 n 行中每一行包含一个仅由 1,2,3 构成的长度为 k 的序列,代表着一张卡片。

保证每张卡片上的序列不同。

输出格式

仅一行一个整数,表示可以组成的本质不同的 SET 的数量。

说明 / 提示

样例 3 解释

可以组成的两个 SET 分别为 (S1,S2,S3)(S1,S4,S5)

数据范围

对于全部数据,满足 1k12,1n3kSi 互不相同且满足 1Si3

Subtask特殊限制分数
1k510
2k730
3无特殊限制70

 

题面(重新翻译了一个新的题面,已经提交到 Luogu)

Examples

Input_1

3 4

1123

1322

1221

Output_1

1

Input_2

2 2

11

22

Output_2

0

Input_3

5 3

111

222

333

123

132

Output_3

2

Solution

需要用到很多 FWT 思想,阅读之前请先完全理解 FWTk 进制 FWT,及用转移矩阵进行变换的 FWT

戳此链接去看刚写完的 FWT

观察题意,发现对于每个 SET 的同一位置的三个数,要么是完全相同的三个数,要么分别是 1,2,3(unordered)

思考这个规律有什么性质

性质1

显然设这三个数为 mi,x,mj,x,mk,x 一定有:

mi,x+mj,x+mk,x0(mod3)

证明:这么显然还需要证明吗

性质2

当这个 SET 中的两个序列被确定之后,第三个序列就有且仅有一种情况,或者说 uniquely determined

证明:一共就三个可能的数,这个也很显然吧

 

然后我们发现这两个性质无法继续向下推,于是我们考虑假设存在一个自洽的代数系统 S,其中只有 1,2,3 三个数字,定义 S 中一种二元运算 ,为了令其符合结合律,我们考虑使其符合以下规律及交换律:

11=122=333=212=213=323=1

同时我们考虑定义一元运算符 mod3,其运算规律与代数系统 (N,mod3),即自然数和 mod3 构成的代数系统相同,详细地表示即为:

1mod3=12mod3=23mod3=0

此时我们会发现更多的性质:

性质3

一个数与其自身进行两次 运算后数值不改变。即:

aaa=a

证明:根据 的定义可知十分显然。

性质4

运算 的交换律与结合律。

证明:显然成立。

性质5

对于性质1,由新的定义可以转化为如下式子:

(mi,xmj,xmk,x)mod3=1

也就是:

mi,xmj,xmk,x=1

此时根据这些性质,如果我们令 F(x) 表示题意中有多少种不同的 triplet 符合对于 x[1,m] 都有:

mi,xmj,xmk,x=x

则显然 F(0) 表示所有不同的 SET 的数量。

(注意这里并不是本质不同,所以也可以理解为 triplet 中三个序列的排列)

这里我们定义序列 gn,有:

gi={0unexist1exist

需要注意下标 i 表示的不是一个数字,而是一个序列,由数据范围可以考虑按位存取,最简单的想法是类似离散化,把它按三进制,压成一个数,也可以考虑用两位二进制存这个数。

存在与否指的是是否在题目给出的 n 个序列中。

容易看出会有如下式子:

F(x)=ijk=xgi×gj×gk

当然这个式子也可以记作:

F=g×g×g

而我们需要的便是这个式子的常数项 F(1),注意这里因为我们的代数系统中不存在 0,但如果我们用三进制离散化压位来存的话,最终需要的就是 F(0),即:

F(0)=ijk=0gi×gj×gk

仔细观察一般的式子,这像什么?显然是多项式的各种快速变换!或者进一步说,很像 FWT

FWT(快速沃尔什变换)一般用于处理形如如下式子的卷积:

C(x)=ij=xA(i)×B(j)

此处的 一般为 &, |, ^, 也就是 and,or,xor

发现我们当前的式子很像 FWT,所以也可以以 FWT 的思想去考虑本题。

FWT 的思路

与大多数多项式快速变换的思路一样,我们的目的都是找到一种变换,对于 FWT 可以考虑记作:

FWT(A)

我们需要让这个变换满足以下性质:

FWT(A)FWT(B)=FWT(C)

且:

AB=C

对于不同的运算都有着与之对应的不同的变换方式,我们的目的就是要找到一种优秀的变换并快速地进行变换。

这里额外说一下对于多项式约定俗成的几种运算表示什么,相信你们一定都知道(主要因为我最开始做这道题的时候有的符号理解错了)

这里我们假设 A 最高次为 N 次,B 最高次为 M 次。

max(N,M)=P

(A,B)=(A(0),A(1),,A(N),B(0),B(1),,B(M))即拼接两个多项式A+B=(A(0)+B(0),A(1)+B(1),,A(P)+B(P))即按位相加AB=(A(0)B(0),A(1)B(1),,A(P)B(P))即按位相减AB=(A(0)B(0),A(1)B(1),,A(P)B(P))即按位相乘,注意不是卷积A×B=(i+j=0A(i)×B(j),i+j=1A(i)×B(j),,i+j=N+MA(i)×B(j))多项式卷积AB=(ij=0A(i)×B(j),ij=1A(i)×B(j),)可以理解为广义上的卷积
本题如何做?

通过上面的信息显然我们便可确定本题的核心:找出在代数系统 S 中运算 的卷积运算时的广义上的 FWT 变换。

从哪入手呢?观察对于常用的三个运算的 FWT 变换式子,我们就会发现这些式子的存在本身就充满着人类智慧,似乎不像是可以很简单推导出来的,但是如果我们从矩阵的角度去考虑,并基于已有的运算的转移矩阵,就可以较为方便的得出结论。

如何推式子?

再次观察我们定义的这个二元运算符

11=122=333=212=213=323=1

题外话:写到这里突然发现我好像推不出来这个式子,于是决定先去把 FWT 的坑填了...

我们要求的可以理解为是以下的式子:

C(x)=ij=xA(i)×B(j)

用和 FWT 一样的思想,因为我们只有三个数,所以可以考虑构造一个 3×3 的转移矩阵,但是注意我们定义的运算 下标从 1 开始,所以与标准的矩阵可能有些差距。

我们需要保证对于转移矩阵 T(i,j) 元,记作 ω(i,j),满足:

ω(x,i)×ω(x,j)=ω(x,k)(ij=k)

观察运算的性质,和三进制下的异或运算性质较为相似,可以考虑尝试范德蒙德矩阵:

[¬¬¬¬¬111¬1ω31ω32¬1ω32ω34]

可以化简为:

[¬¬¬¬¬111¬1ω3ω32¬1ω32ω3]

逆矩阵同理容易得出为:

13[¬¬¬¬¬111¬1ω31ω32¬1ω32ω31]

可以化简为:

13[¬¬¬¬¬111¬1ω32ω3¬1ω3ω32]

显然我们可以算出:

ω3=cos(2π3)+sin(2π3)i=12+32i

且:

ω32=(12+32i)2=1232i

到此我们便可以求出来最终的结果了。

这里还有两个小细节需要注意:

两个小细节

首先我们在做完 IFWT 之后需要乘一个 13,我们当然可以每次都做一个除法,但是观察发现,项数需要满足 3n 形式,而层数也就是 log33n=n,所以也可以在最后答案除一个 3n(和 FFT 挺像的),不过属于常数优化,差别不大。

然后还需要注意当我们算出来常数项之后,并不能直接输出,观察一下性质 3:

aaa=a

在运算的时候我们显然会把 i=j=k 的情况算在内了,而显然这是不合法的,所以需要减掉 N

并且,我们在运算的时候求的是不同,而非本质不同,也就是算的是排列,而我们要求的是组合,所以最后除一个 3!,也就是 6

综上所述,我们将常数项算出来后最终答案就是 F(0)N6

至此,这道卡了我两天多的题,终于结束了。

(记得开 long long

Code

T5 Volontiranje

这题比 T4 简单多了。

题面

给定一个长度为 n 的排列,求最多的不交叉最长上升子序列的(即每个数只能用一次)。(是的就这么简洁)

输出个数,长度,并输出每一个最长上升子序列。 n106

Examples

Input_1

3

1 2 3

Output_1

1 3

1 2 3

Input_2

4

4 3 2 1

Output_2

4 1

1

2

3

4

Input_3

7

2 1 6 5 7 3 4

Output_3

2 3

1 3 5

2 6 7

Solution

考虑求 LIS 的长度直接 O(nlogn) 求即可,可以用 lower_bound 求。

而对于有哪些 LIS,我们则需要找到其中的一些性质,考虑将每个数的下标作为 x,数值作为 y,把每个数丢到二维坐标系里面观察性质,比如对于 Input_3,最后会形成下图:

COCI-Contest1_1.png

观察这个奇怪的图形我们可以考虑从 x=1 开始划分层级,把 x 递增而 y 递减的点与初始点划分到同一层级。

也就是如下:

COCI-Contest1_2.png

注意这里的层级划分是左下开右上闭的。

于是我们便可以发现,对于每一个 LIS 都应该是从每一个层级中选择一个点并且符合,下一层级的点符合在当前点的右上。

这里我们考虑如何分层,考虑当我们计算 LIS 时,一般用的状态是,以当前点为结尾的 LIS 长度,我们观察发现,第一层级里,A,B 长度一定为 1,第二层级里,C,D,F 长度一定为 2E,G 长度一定为 3

于是我们便可以发现按照 LISi=k,对于同一个 k 的所有下标 i 作为同一层级。

让后我们考虑如何选择每一层级的点,这里我们有一个结论,对于每一层级优先选择纵横坐标,也就是下标更低的未选择过的点一定是更优的,这个正确性可以去举例理解一下,如果对于上图的情况,连结 ADBC 和链结 ACBD 都可以符合要求,是两组不同的合法解,但是考虑如下情况:

COCI-Contest1_3.png

(这里为了方便表述省略了一些点)

显然层级划分的线大概是这样,这个时候如果我们对于 A,使其连结横坐标更小的 C,会使 BD 也是一组合法解,而如果连结 AD,则 BC 不合法。故显然优先连结未选择里面横坐标更小的是最优方案。

至此我们的推导已经结束,可以进行实现了。

Code

UPD

update-2022_08_30 T1-T3

update-2022_09_01 完成一部分的 T4

update-2022_09_02 T4 肝完

update-2022_09_04 初稿

update-2022_09_04 发现 T4 之前算法假掉了,修改了一下

update-2022_09_06 完善 latex 以符合 Luogu 题解要求