UOJ Logo peehs_moorhsum的博客

博客

UOJ NOI Round #4 Day2 题解

2020-08-13 13:42:39 By peehs_moorhsum

这次的题目背景大部分是vfleaking写的。

出题人 01,02,03 只是主人公的名字,和真实出题人没有任何的关系。

同构判定鸭

from Picks,标程 by Aprilgrimoire,数据、题解 by zhouyuyangvfleaking

算法0

这题好不可做啊!

交个简单的代码跑路吧:

print 'Same'

期望得分:$0$

算法1

我会爆搜!

在wc上学了高超的搜索技巧感觉充满了力量!

期望得分:$15 \sim 35$。

算法2

对于 DAG 的情况,显然若存在坏串则坏串长度不超过 $\max\{n_1,n_2\}$。

适当选取一种对字符串集合的哈希函数之后,我们就可以对于每一个结点 $v$ 和每一个 $k$,递推计算出从 $v$ 出发可匹配的且长度为 $k$ 的字符串集合的哈希值。然后就容易根据哈希值计算出坏串的最短长度了。

输出字典序最小的最短坏串可以通过按位贪心来实现。

时间复杂度$O(n^2m)$或$O(nm)$。

期望得分:$20 \sim 40$。

算法3

DAG 的情况启发我们去思考:如果存在坏串,那么最短的坏串长度是否比较短呢?

注意如果不是比较短的话,题目也不会让我们输出方案的。不然岂不是出题人亲自邀请大家炸测评机?

实际上我们确实能证出如下结论:

结论:如果存在坏串,则最短的坏串长度不超过 $n_1+n_2$。

证明是这样的。首先我们可以把 $G_1, G_2$ 拼成一个$n_1+n_2$个点的大图 $G$($G_2$ 的结点编号都加上 $n_1$)。给定一个字符串 $s = s_1s_2 \cdots s_L$,想统计 $s$ 在 $G_1$ 和 $G_2$ 中的出现次数之差,我们可以用 $f_{k,v}$ 表示 $G$ 中长度为 $k$ 且与 $s_1 \cdots s_k$ 匹配且最后一个结点是 $v$ 的路径条数,然后递推求出 $f$。最后如果 $$ \sum_{1 \le v \le n_1} f_{L,v} - \sum_{n_1 < v \le n_1 + n_2} f_{L,v} = 0 $$ 则出现次数相等,否则不相等。

仔细分析递推式可以发现这是个线性的递推式,且相同的 $k$ 的转移只跟 $s_k$ 和 $v$ 有关。那么我们可以把转移写成 $26$ 个矩阵 $M_a, M_b, \cdots, M_z$。若把初始的 $f_{0, v}$ 写成一个行向量 $u_I^{\top}$(一个元素均为 $1$ 的行向量),那么最终 $f_{L, v}$ 就是 $u_I^{\top}M_{s_1}M_{s_2} \cdots M_{s_L}$。令 $u_O$ 为前 $n_1$ 个元素都是 $1$,其他元素都为 $-1$ 的向量,则 $s$ 在 $G_1, G_2$ 中出现次数相等当且仅当 $u_I^{\top}M_{s_1}M_{s_2} \cdots M_{s_L} u_O = 0$。

现在我们令 $V_K$ 为所有 $L \le K$ 的 $s$ 对应的行向量 $u_I^{\top}M_{s_1}M_{s_2} \cdots M_{s_L}$ 组成的集合。如果 $G_1, G_2$ 不等价,就说明存在一个 $K$ 使得 $V_K$ 内有元素 $u^{\top}$ 满足 $u^{\top} u_O \ne 0$。

下面要用到一点点向量空间的概念。对于一个行向量集合 $V$,我们用 $\mathrm{span}(V)$ 表示所有 $V$ 中元素的线性组合组成的集合,也即 $V_K$ 张成的向量空间。数学表达式为: $$ \mathrm{span}(V) = \left\{ \sum_{i=1}^{m} \lambda_i u_i^{\top} : m \ge 1, u_1^{\top}, \cdots, u_m^{\top} \in V, \lambda_1, \cdots, \lambda_m \in \mathbb{R} \right\} $$ 比如共线的向量张成的是一条线,共面的向量张成的是一个平面。对于每个 $V_K$,我们令 $U_K = \mathrm{span}(V_K)$。容易看出,$V_K$ 内有元素 $u^{\top}$ 满足 $u^{\top} u_O \ne 0$ 当且仅当 $U_K$ 内有元素 $u^{\top}$ 满足 $u^{\top} u_O \ne 0$。

对于一个行向量集合 $V$ 和一个矩阵 $M$,我们用 $VM$ 表示 $\{ u^{\top}M : u \in V \}$。那么 $V_K$ 是可以递推的:$V_K = V_{K-1} \cup \left(\bigcup_{c \in \{\texttt{a}, \cdots, \texttt{z}\}} (V_{K-1} M_c)\right)$。因此 $\mathrm{span}(V_K)$ 也是可以递推的: $$ U_K = \mathrm{span}\left(U_{K-1} \cup \left(\bigcup_{c \in \{\texttt{a}, \cdots, \texttt{z}\}} (U_{K-1}M_c)\right) \right) $$

根据定义,$U_1 \subseteq U_2 \subseteq U_3 \subseteq \cdots$。那么 $U_K$ 是否会随着 $K$ 的增大而一直变大呢?根据向量空间的性质和上面的 $U_K$ 的递推式,答案是不会的。

这里要用到向量空间的维数的概念。直观上一个向量空间 $U$ 的维数就是你直观所以为的那个维数(线是 $1$,面是 $2$)。数学上,维数的一个等价定义是你在 $U$ 中最大的线性无关组的大小。其中线性无关组是指一组向量 $u_1, \dots, u_d$,满足性质:任意线性组合 $\sum_{i=1}^{d} \lambda_i u_i$ 等于 $0$ 当且仅当 $\lambda_i$ 全为 $0$。对于两个有限维的向量空间 $U \subseteq U'$,可以证明要么 $U$ 的维数比 $U'$ 大,要么 $U = U'$。这是因为 $U \ne U'$ 的时候我们可以取一个 $u' \in U' \setminus U$ 加到 $U$ 的最大线性无关组里,就得到一个 $U'$ 的线性无关组了。

显然,$U_K$ 的维数不会超过 $n_1 + n_2$,因为这些向量就 $n_1+n_2$ 个坐标嘛。因此,$U_K$ 的维数先会随着 $K$ 严格单调递增,然后到某个 $K = K^{\ast}$ 时 $U_{K^{\ast}} = U_{K^{\ast} + 1}$,且这里 $K^{\ast} \le n_1 + n_2$。根据递推式我们可以看出相同的 $U_{K-1}$ 一定推出的是相同的 $U_K$。所以一旦 $U_{K^{\ast}} = U_{K^{\ast} + 1}$,则 $U_{K^{\ast}} = U_{K^{\ast} + 1} = U_{K^{\ast} + 2} = \cdots$ 大家都相等了。这就说明如果存在 $U_K$ 内有元素 $u^{\top}$ 满足 $u^{\top} u_O \ne 0$,则最小的 $K \le n_1 + n_2$,就证好啦。

细节不太清楚的可以去找本自己看得懂的线性代数教材瞧瞧向量空间的具体定义。不知道是否有不依赖于线性代数的证明,如果有的话欢迎分享下咯。

回到算法上来。现在我们知道了,如果对于所有长度不超过 $n_1+n_2+1$ 的序列均合法则可以对于所有串均合法。

因此可以通过哈希确定坏串最短长度后即可按位确定答案。

时间复杂度$O(n^2m)$或$O(nm)$。

期望得分:$70 \sim 100$。

我和算法3一样为什么我挂掉了

你的哈希函数 $H$ 需要满足:$H(\texttt{"ab"}) \neq H(\texttt{"ba"})$ 且 $H(\texttt{"bc"})+H(\texttt{"de"}) \neq H(\texttt{"be"})+H(\texttt{"cd"})$,否则你的算法就会是错的。

Aprilgrimoire 在验题的时候加了一个extest把这种情况干掉了

一些正确的哈希姿势

例如从后往前数,位于不同位置的相同字符有着不同的哈希值。字符串的哈希值就是字符哈希值的乘积,多串的哈希值是每个串哈希值的和。

另一种方法是把字符串的哈希值设为 $\mathrm{b}^{\sum_{i} s_i a^i}$,然后多串的哈希值还是每个串哈希值的和。

还有一种方法是把哈希值设成矩阵的形式,例如每个字符都对应一个 $3 \times 3$ 的随机小矩阵。

OIer 当然可以使用反正法说明哈希的正确率:“反正哈希正确率很高!” 但我们这里还是分析一下第一种方法。

第一种方法即事先随机出 $x_{i,c}$ 共 $(n_1+n_2) \times 26$ 个随机数,然后每个字符串的哈希值即 $H(s_1 \cdots s_L) = \prod_{i=1}^{L} x_{L-i+1,s_i}$。我们递推求出的是对于每个 $L \le n_1+n_2$,两个图各自对应的哈希值:$f_1(L) = \sum_{s_1 \cdots s_L} g_1(s) H(s)$ 和 $f_2(L) = \sum_{s_1 \cdots s_L} g_2(s) H(s)$。这里我们用 $g_1(s), g_2(s)$ 表示 $s$ 在 $G_1, G_2$ 中的出现次数。

现在我们将 $x_{i,c}$ 看成变量而非随机数,则 $f_1(L, x), f_2(L, x)$ 都可以看作是 $x_{i,c}$ 的 $L$ 次多项式。不存在长度为 $L$ 的坏串,等价于 $f_1(L, x), f_2(L, x)$ 作为两个关于 $x$ 的多项式时是相等的(也即多项式系数相等,也即这两个函数在带入任意一组 $x$ 的时候都相等)。

因此就是要看看两个多项式不相等,但随机一组 $x$ 带入进去之后导致 $f_1(L,x) = f_2(L, x)$ 的概率是多少。我们可以用 Schwartz-Zippel 引理来说明:对于某个域 $F$ 上的不超过 $d$ 次的多项式 $f(x_1, \dots, x_m)$,如果每个 $x_1, \cdots, x_m$ 都是从 $F$ 中的一个大小为 $S$ 的子集中独立地均匀随机选取的,那么 $f(x) = 0$ 的概率不超过 $\frac{d}{S}$。

对于本题,大家当然会在模一个素数 $p$ 的情况下计算。令 $F = F_p, f(x) = f_1(L, x) - f_2(L, x), d = n_1 + n_2, S = p$,就可以知道失败概率不超过 $(n_1+n_2)/p$。

但这个失败概率仅仅是做一次“用哈希值相等来判断两个字符串集合相等”的失败概率。算法中我们要枚举长度,还要按位贪心,所以大概要做 $O((n_1 + n_2)\Sigma)$ 次,其中 $\Sigma$ 是字符集大小。使用 union bound 可知总的失败概率是 $O((n_1+n_2)^2 \Sigma / p)$。取个大点的 $p$ 就可以高枕无忧啦。

对这个问题有兴趣的同学可以搜一下 Polynomial Identity Testing (PIT) 学习一波。

Bonus

如果要求严格字典序最小,能否证明在存在严格字典序最小的情况下,答案串长度是否有限?若有限,答案串长度是否存在上界?

己酸集合

from zhouyuyang,数据、标程、题解 by zhouyuyang

把题目名字的拼音拿出来,JiSuanJiHe,这提示了这是一道计(Ji)算(Suan)几(Ji)何(He)题。

算法0

我会暴力!

每次询问暴力计算答案!

期望得分$15$。

如果利用算法$2$中的方程判断,可能可以通过Subtask $3$。

算法1

我会KD-Tree!

随机数据KD-Tree的复杂度看上去很真实。

极端情况下会被卡到$O(nQ)$,但是跑跑subtask $2$应该没啥问题。

事实证明KDT是一个死掉的算法。

期望得分:$45$。

算法2

我会写方程!

写出圆方程$x_i^2+(y_i-z_i)^2 \le R_i^2$。

移项得到$x_i^2+y_i^2 \le R_i^2-z_i^2 +2y_iz_i $。

如果我们把$(x_i,y_i)$映射到$(y_i,x_i^2+y_i^2)$,则问题转化为询问直线$l:kx+b$以下的点个数。其中$k=2z_i,b=R_i^2-z_i^2$。

维护斜率固定时的点的相对顺序,每次询问二分即可。

时间复杂度$O((n^2+Q)\log n)$。

期望得分:$30$,结合算法$1$期望$60$。

算法3

欸$n=12000$好像不太能继续用算法$2$了。

欸能不能把$n$给分成若干块,每块单独计算贡献。

如果按照分块的思路去维护,设把点序列分成$S$块,每一块按照算法$2$的思路来处理,则时间复杂度为$O((\frac{n^2}{S}+QS)\log n)$。

取$S=\frac{n}{\sqrt{Q}}$时最优,为$O(n\sqrt{Q}\log n)$。

期望得分:$100$。

我和算法3一样为什么我又挂掉了

坐标范围是$10^9$因此用 double 精度有可能会爆炸。

出题人没有说过点集互不相同,公告里也更新过了,所以对于相同点要又高超的处理技巧。

可能将点坐标转换后会出现三点共线,同时sort是不稳定排序,因此需要一些小技巧处理这种情况。

挑战哈密顿

from peehs_moorhsum,数据、标程、题解 by peehs_moorhsum

算法0

我会暴力!

暴力搜索哈密顿路径,或者状压DP,可以通过前两个点。

期望得分$20$。

算法1

第三个点是$DAG$,第四个点缩强连通分量之后每个分量很小。

可以对于每个分量搜任两点之间有没有哈密顿路。

期望得分$40$。

算法2

第五个点到第十个点是在一条链上随机加边生成的。

有各种乱搞姿势,看起来能在这些点获得10~57分不等

结合算法1,可以获得50~97分

算法3

接下来是标算。

维护边的一个尽量大的子集,满足只考虑这些边时每个点出入度都不超过1,且不构成圈。

如果子集大小达到$n-1$,则找到了一条哈密顿路。

考虑调整维护子集。按随机顺序考虑边,如果加入后不构成圈,且加入之后所有点度数均仍合法,则加入这条边。

否则如果不构成圈,但有一个点度数不合法,则以一半概率加入并把该点相连的与新加入边矛盾的边断掉。

用最暴力的方法实现,也能总用时在10秒左右跑出前9个点,10分钟左右跑出最后一个点。

期望得分:$100$。

如果利用LCT维护是否构成圈,能够快很多。但出题人因为太懒,并没有写

一些彩蛋

关于有向图哈密顿链,似乎是有不少论文的。

验题人实现了其中一些,发现都是反向优化没有很好的表现。

所以欢迎吊打论文的大家在题解区交流做法ww

另:这道题主角真的是03

评论

DownDownDown
前排
zhouziheng
T3又是毒瘤提答题……和那个三染色一样……
EntropyIncreaser
一个奇怪的 hash 想法:给每个字符随机赋予一个在 $\mathbb F_p$ 上的 $k\times k$ 矩阵,这样就不会直接满足交换律,并且看起来能支持更一般情况的字符串集合的 hash 功能,比如把两个集合里的串两两拼接构成的一个乘积形式的集合什么的。看起来 $3\times 3$ 的随机矩阵通过了目前的数据(
memset0
跑路被发现了[大哭][大哭][大哭]
luosiyuan
t2算法二期望得分是45吧(
rojer
前排支持
disangan233
前排自闭
EndSaH
kdtree 怎么找圆内点数。。不太会
Itst
前排声明:那个提答 97pts 的是 gcz 不是我 /fad
Samcompu
看第三题随机算法跑 NP,想到一篇 [CF 的文章](https://codeforces.com/blog/entry/81024)
1tst
@zhouyuyang http://a1b3c7d9.blog.uoj.ac/blog/5263
nealchen2003
计算几何无细节做法:直接按整数击败时间做。重合点、三点共线都不用判(然而负数除法下取整写成向零取整FST了/kk)
panyf
T2算法3时间复杂度错了吧,应该是$O(((\frac{n}{S})^2+QS)\log n)$
zx2003
话说T1正确率咋分析啊。
fuyuki
T1 用普通 hash + 判断最后一个字符可以 AC。。这样能 hack 吗?http://uoj.ac/submission/425864
ouuan
“反正法”草

发表评论

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