UOJ Logo WuHongxun的博客

博客

UOJ Test Round #3 题解

2017-11-19 22:25:53 By WuHongxun

其实写题面的时候埋了不少彩蛋啊?大家可以试一试能找出几个?

几何冲刺

出题人 ftiasch

数据和题解 WrongAnswer

验题人 matthew99

算法一

对于每对红点 Pi,Pj,暴力枚举蓝点 Qk 判断其是否在三角形 OPiPj 内。

如何判断 Qk 是否在三角形 OPiPj 内?只需判断三角形 OPiQk、三角形 OPjQk、三角形 PiPjQk 的面积之和是否等于三角形 OPiPj 的面积即可。以 (x1,y1),(x2,y2),(x3,y3) 为顶点的三角形面积为 12|x1(y2y3)+x2(y3y1)+x3(y1y2)| 这样就能每次 O(1) 完成判断了。时间复杂度 O(n2m),期望得分 32 分。

算法二

考虑将问题进行转化。

注意到点 Qk 在三角形 OPiPj 内的条件是点 Pj,Qk 在直线 OPi 同侧,且 QkOPi<PjOPiQkPiO<PjPiO。于是可以枚举 Pi,枚举直线 OPi 的一侧,然后把每个红点和蓝点 X 当成一个二元组 (a,b),其中 a=XOPib=XPiO。然后枚举点 Pj,就只需找出 a,b 两维均比 Pj 小的蓝点了。

按其中一维排序,用数据结构(如树状数组或set)维护另一维即可。具体实现方式是按其中一维从小到大顺序扫描每个点,如果是蓝点则插入数据结构,如果是红点则在数据结构中查询另一维比该点小的蓝点。时间复杂度 O(n(n+m)logm),期望得分 78 分。

算法三

算法二还可以进一步优化。

我们可以一开始以原点 O 为中心,将所有点(包括红点和蓝点)进行极角排序。

之后枚举点 Pi 时,每个点的 a 这一维已经有序。由于对非空三角形只要找出任意一个内部的蓝点,因此在按 a 从小到大枚举 Pj 时不需要要数据结构维护蓝点,只需用一个变量维护扫描到的蓝点中 b 最小的点即可。

这样时间复杂度为 O(n2+nm),期望得分 100 分。

去月球

出题人 WuHongxun

数据和题解 Scape

验题人 worse

算法 1

首先我们先来证明一个结论 即最终答案和消除顺序无关。

如果在某个时刻删掉了..xx..会使答案变差,那么说明更优解应该是其中的某个x和一个另外的x配对了,不失一般性地,我们设是左边这个x

那么在删左边这个x之前,序列的样子应该是..xxx..,这时候我们注意到删左边这对xx和删右边这对xx之后结果的是一样的,所以答案并不会变大。

对于这个结论也有一个wiki

那对于每个询问,我们都拿一个栈暴力跑一遍就可以知道答案了

时间复杂度O(nq),期望得分20

算法 2

我们考虑Subtask 2

我们显然只要考虑出现了两次的括号

对于某个出现了两次的权值i,设第一次出现在li,第二次出现在ri

那么对于某个询问L,R,这对括号被消除当且仅当[li+1,ri1]是可消除的并且liL,riR

判断是否可消除可以直接建一棵树来判断。

而第二个约束是显然可以通过二维数点来实现的。于是这个Subtask就被解决了。

算法 3

Subtask 3是给离线做法的,我们先来考虑离线。

我们进行分治,对于当前分治区间[L,R],我们只处理过中点的询问。

我们设中点是mid,那么对于[L,mid]的每个后缀区间和[mid+1,R],我们都用一个栈维护出他们消除后的答案。

考虑把两个区间合并,新发生的消除显然只会是前面区间的某个后缀和后面区间的某个长度相同的前缀翻转过来完全相同。我们接下来就是要求一个lcp。

考虑怎么求lcp,[mid+1,R]的长度为i+1的前缀消除后的结果要么是长度为i的前缀删掉最后一个字符或者是在最后面加上一个新的字符。那么我们用trie来保存这个结果。求lcp就是求两个对应节点的LCA。

而在线就显然只需要把每个区间的trie和结果都存下来,对于每个询问都去对应的分治区间查询。

那么我们如果用倍增/树剖去求LCA,我们可以做到O(nlog2n+qlogn),基本上可以得到100分。

如果我们用RMQ去求LCA,我们可以做到O(nlog2n+q)

如果更丧病一点用O(n)O(1)LCA,我们可以做到O(nlogn+q)

标算用的是RMQ求LCA。

但是还有一个小细节是如果我们想要做到每个询问回答是O(1),我们还要做到快速定位到询问区间

我们有两个做法,第一个做法是分治实际上就是一棵线段树,那么某个询问对应的分治区间实际上就是他们的LCA,我们用O(1)回答的LCA就可以做到。

或者我们也可以用一个更简单的方法,我们把分治这棵线段树开到2171,这样对于询问L,R,他们会在L xor R的highbit上分开。

这题80分的Subtask大概是给一些分块做法和询问需要log2的做法的(比如二分hash)。

算法4

from matthew99

考虑我们像算法二那样建一棵操作树,保证对于这棵树的每个子树都是可以完美消除的。

我们直接类似算法三分治后建trie的做法,我们从左往右扫,如果当前字符和栈顶匹配就回到父亲,不然就把当前字符压到栈内并且走到对应的儿子。

对于这棵树,我们从任意一个节点出发,经历一个可完美消除的序列后,它都一定会回到这个节点本身。

所以对于某个询问[L,R],答案就是RL+1再减去他们在这棵树上的距离。

正常的写法是O((n+q)logn)

如果用hash_map和O(n)O(1)LCA的话,可以做到O(n+q)

具体实现细节可以参考这个submission

量子破碎

出题人 WuHongxun

数据和题解 WuHongxun

验题人 fateice

算法0

我们用操作4,暴力O(2n)的问出来每个a[i]就好啦。

算法1

我们考虑怎么优化这个暴力。

我们可以注意到我们大部分的时间都在查空的a[i],如果我们只关注一位,不妨把别的位都变成0,然后查一查这一位上xor是0还是1。

注意AAt=I意味着,At=A1,从而A一定是可逆的。

而把所有别的位都改成0不是一个可逆的操作,所以肯定是无法用2实现的。

我们只好用操作3来做到把除了第i位之外每一位强制为0,作用上矩阵(1010)

然后用操作4查一下a[0]a[2i]即可。

因为要对每个i做一次,复杂度O(n2)

算法2

我们考虑如何丢掉算法1里的最后一步用操作4查a[0]a[2i]

如果直接随机,那么无论xor是0还是1,都会随机返回0或1(每次x会重新随机)。

为了区分出来我们做变换a[0]:=a[0]+a[2i]a[2i]:=a[0]a[2i], 也就是应用矩阵(1111)

这样如果xor是0,那么一定会返回0,否则会随机返回0或1。

随机多次判断即可,复杂度O(n2)有较大的常数。

算法3

fateice 在验题时提出一个hack。注意题面里有提到交互库的实现,会在概率平方和为0的时候返回0。

如果平方和不为0,返回0的概率很小。

那么只要每次把一位做变换a[0]:=a[0],a[1]:=a[0],如果返回了0,那么说明xor为0,否则说明xor为1。

(1010)

复杂度O(n)但同样是概率算法。

算法4

我们考虑对每一位i都做算法2中的变换a[0]:=a[0]+a[2i]a[1]:=a[1]a[2i],这样a[0]就会变成所有a的和。

如果我们在变换前枚举第i位,把它的a[0]:=a[0],a[1]:=a[1],也就是作用矩阵(1001)

那么变换后如果这位xor为0,那么a[0]会变为0,否则一定不是0

最后一步用操作4查一下a[0]就好啦。

询问复杂度O(n2)

算法5

@fateice 在算法1上稍微修改一下,丢掉操作3的玄学做法。

我们可以对旋转矩阵,(cos(x)sin(x)sin(x)cos(x))随机取几个x

然后对除了第i位之外的每一位做这个变换,然后随意找一个位置x用操作4查出a[x],a[x(1<<i)]。如果同时有值就说明了xor为1。

算法6

我们思考一下算法4,不难发现这其实是一个fwt!算法2中我们用它得到了一些non-trivial的信息,算法4中我们用a[0]的信息得到了一个部分分做法,a[t]的信息丢掉非常可惜,我们不妨思考一下它能告诉我们什么?

考虑fwt中xy的贡献,显然绝对值肯定是1,由于fwt的矩阵只有 A[1][1]=1。所以贡献的权值等于 (1)x&y

fwt之后位置t的值等于 (1)x&t+(1)y&t

0 当且仅当 x&t=y&t,根据F2下的乘法分配律也就是 (xy)&t=0

所以我们 a[t]0 当且仅当t和答案的and有偶数个1!

我们是不是随机线性无关的 nt 就可以解出答案了呢?

很可惜,这些t并不是满秩的!比如说当答案是二进制11的时候,t只能是001100没有用,也就是说最大秩为n1

因为每一维选不选定为ci的话,我们其实有一个限制若干个ci(ans为1的那些ci)异或起来为0,所以秩只有n1

不过这只是偶数的情况,如果我们把它变成and有奇数个1,那么我们可以用1001构成一组满的基!

考虑怎么变成奇数个1,只要在一个xor为1的位,应用算法4中的变换 (1111) 即可。

我们每次枚举一位,然后应用变换 (1111) 之后,用fwt随机O(n)个t,然后高斯消元判断一下秩是n还是n1即可知道这一维是不是1。(考虑答案中只有一位是1的情况,就算在满秩情况接出了所有位,最差情况总是要枚举每一位)

询问复杂度O(n3)

算法7

我们用另外一个方向理解一下为什么秩只能有n1,因为所有xy=0始终都会是xor方程的解。

xor方程组始终都有两个解xy0,所以秩为n1

但是我们知道答案不可能是0,所以把它丢掉取xy输出即可。

期望要随机O(n)个随机向量会满秩,实际上更接近n+1

询问复杂度O(n2),期望得分100分。

算法8

matthew99在验题的时候,猜想是fwt,于是,fwt之后暴力枚举2n直到方程只有一个解。

询问复杂度O(n2),算法复杂度O(n2n)。期望得分100分。

由于交互库很慢,所以只能让这种做法通过了。不过思考到fwt,可以说已经解决了这道题的一半了。

题目背景

其实这道题目相当于给出n个纠缠的量子比特,你每次可以旋转翻转(正交变换)其中一个量子或者是做一次观测(然后会坍缩到一个态)。

如果把题目中2×2的矩阵换成一个23×23的矩阵作用在三位上,并且允许振幅是复数,就是量子计算的理论模型了。

这个算法其实正是量子计算机上寻找循环节的Simon算法,正是这个算法启发了著名的Shor算法。

FWT和高斯消元从入门到精通

评论

前排
辛苦啦
评论回复
WuHongxun:哇谢谢pls
撒花~
话说一次round三道交互题?(也许是这次TestRound特性)
评论回复
WrongAnswer:公告里明确了三道交互题……
前排资磁,但是**题目链接**好像有点问题...
评论回复
WuHongxun:thx
第二题后缀数组求LCP和暴力分一样。。 虽然复杂度也是nlog^2n+qlogn 惨啊。。
评论回复
peehs_moorhsum:就是..把线段树每个节点的残留物依次排放,就产生了一个长度为nlogn的字符串 对其建后缀数组
peehs_moorhsum:但是我的后缀数组板子常数太大了。。 导致预处理直接炸飞 为什么不给一些n小一点的点啊。。QWQ
peehs_moorhsum:具体实现看我比赛中代码就行了
WuHongxun:回复 @peehs_moorhsum:因为std是q的啊
peehs_moorhsum:回复 @WuHongxun: 好吧QwQ 可我还是觉得100000的nlog^2n有点卡常啊。。 (虽然用DC3能少个log)
@WuHongxun 题解里的题目链接挂掉啦!
评论回复
WuHongxun:thx
求彩蛋是什么
评论回复
skyline:是UNR2的3道题吗?
WuHongxun:回复 @skyline:不止
skyline:回复 @WuHongxun:是还有蚯蚓队列吗
WuHongxun:回复 @skyline:还是不止哦
skyline:回复 @WuHongxun:好像还有逛公园?
T1,我用极角排序+用set贪心优化了一下O(n^3)的暴力算法,结果过了subtask2, 然而我觉得这极限应该能卡到O(n^3),有没有dalao来hack一下或者证明一下复杂度啊,谢谢! 提交记录:http://uoj.ac/submission/205717
这个T3为什么算法时间复杂度是O(n22n),我感觉是O(n2n)
评论回复
WuHongxun:回复 @zx2003:fixed
哇这个C题的链接点进去怎么是B题啊
评论回复
WuHongxun:fix了(才看见

发表评论

可以用@mike来提到mike这个用户,mike会被高亮显示。如果你真的想打“@”这个字符,请用“@@”。