UOJ Logo zhoukangyang的博客

博客

暂别

2024-08-30 18:16:29 By zhoukangyang

一年接一年,又到了 UOJ 管理员的换届时刻!

我们这一届管理员(1kri, huahua, JohnVictor, zhoukangyang)在过去的一年中举办了一场 UR,一场UR,以及年度活动 Goodbye Round 与 UNR。多亏了为我们提供指导与帮助的 vfk vfleaking 与前管理 qingyuskip2004,帮我们上传了大量题目的 Rainbow_sjy, 以及这一年来为 UOJ 分享自己有趣的题目的 command_block, cmll02, Kubic, tzc_wk, Ecrade_, zjy0001myee。在无数的命题、造题、传题与修锅的过程中,是这个大家庭对 UOJ 共同的热爱,指引着我们又走过了一年。

当我是刚学 OI 的小朋友时,我便与 UOJ 第一次邂逅。当时我参加了 UOJ Long Round #1,鏖战四个小时终于通过了 T1,而在这题之后还有五道更难的题目,我感受到了这个 OJ 的深不可测。后来我在做 UOJ 比赛题的时候,我发现这些题目的质量普遍较高。这些题目常常蕴含着一些独特而惊艳的思想,这些思想让我受益匪浅。一代一代的管理员用自己纯粹的热情传递着 UOJ 的精神,打造着属于一代一代选手的思维乐园。

在 NOI 2023 结束前,青鱼与 127 找到了我,问我有没有兴趣来当 UOJ 管理员。出于对这个伟大 OJ 的热爱,我毅然决定接下了这个大锅。回顾当管理的一年,许多事情让我记忆犹新。UR26 比赛时我发现 T2 的一个子任务数据范围配错了,好在样例没问题,没对比赛造成影响;在 UR27 前,为了让这场比赛的 T3 不被浪费(我计划在 APIO 讲这道题)且让尽可能多的选手能参赛,我们反复地商讨比赛时间;还记得 UNR Day2 的前一天我还在参加 AWTF 的现场活动,而我还没完全造完我的题目,因此我没去最后的 KTV 活动,而是回到酒店造题造到凌晨;今天我试着将自己的账号封禁再用其他超管的账号把自己解封,却发现自己已经不再是超管了,这给我的我的 UOJ 管理任期画上了一个滑稽的句号。

我们相信下一届管理员能够比我们做的更好,将 UOJ 的这份精神继续发扬光大,建设这一算法竞赛的圣地。在接下来的一年中担任 UOJ 的管理员的四位分别是:

Rainbow_sjy, shr, yaoxi_std, Melania

祝你们四位一切顺利,祝 UOJ 有更光明的未来!

UOJ NOI Round #8 Day2 题解

2024-07-14 14:27:00 By zhoukangyang

D2T1

idea,solution,data,std by zhoukangyang

这题有很多做法,欢迎大家在评论区交流。

考虑设 $t_i$ 表示 $i$ 被删除的时间。

考虑从前往后依次确定 $t_i$。如果 $i$ 时刻在 $t_i$ 时刻被删掉,那么 $i$ 前面的第一个 $\ge t_i$ 的 $t$ 上的字符一定和 $i$ 不同。而 $t_i$ 是满足条件的值中最小的一个。

所以可以考虑对于每个 $j$ 记录 $i$ 前面第一个(下标最大的一个)满足 $t_{pos}\ge j$ 的 $s_{pos}$。

考虑记录该字符串。初始状态就是整个字符串均为 $s_1$。

加入位置 $i$ 的时候,修改即为在字符串中找到第一个 $\neq s_i$ 的字符 $p$,将其修改为 $s_p$。如果找不到则说明该位置不会被删除。

直接用动态规划维护是 $\mathcal O(n2^k)$ 的。

注意到我们其实只关心字符串中 $1$ 的个数!这样就能做到 $\mathcal O(nk)$ 了。

思考题:如果 $s_1$ 也会被删除该怎么做?(这题也能做到 $\mathcal O(nk)$。)

D2T2

idea,solution,data,std by zhoukangyang

致歉

本来这题是 $n\times n$ 矩阵找第 $n$ 小,只允许比较,要求次数 $\mathcal O(\sqrt n)$,放 Day2T3 的。

但是后来因为常数太大,卡不掉暴力,就改成了现在这个版本。

结果这题之前在一些地方的模拟赛里面出现过了,赛前没有查到一样的题,向大家道歉!!

题解

考虑提取所有偶数列,然后求出其中第 $(k-n)/2$ 小值。我们发现最后的答案一定大于等于这个值,所以前 $k$ 小的元素中我们已经确定出了 $(k-n)/2\times 2$ 个了,还差 $n$ 个。

现在我们只需要接下来再取出 $n$ 个元素即可。这个可以把每行第一个没被选的元素丢到 priority_queue 实现。

行列交替地做,操作次数是 $T(n,m) = T(m,n/2) + 2n$,有 $T(n,n)=6n$,还不能通过(然而数据较弱,部分选手直接实现了这个算法也通过了)。

我们发现如果 $(x-1,y)$ 和 $(x,y-1)$ 还没被选进前 $k$ 小,$(x,y)$ 就暂时不会被选。事实上,加上这个优化操作次数就是 $5n$ 的了。

我们证明从 $T(n/2,n/2)$ 的答案推到 $T(n,n)$ 的过程中我们最多只会问 $2.5n$ 次。

证明:考虑 $T(n/2,n)$ 到 $T(n,n)$ 的过程。设第 $i$ 行刚开始去了 $a_i$ 个元素($a_i$ 是偶数),最终取了 $b_i$ 个元素,那么最终我们会问 $n+|\{b_i\}|$ 次。在 $T(n/2,n/2)$ 中,我们询问了 $n/2 + |\{a_i\}|$ 次。;

我们先假装总询问次数是 $3n/2 + n + |\{a_i\}|$ 次,接下来观察我们会在什么情况下少问一些。

在做 $T(n/2,n)$ 时,如果 $a_i\neq a_{i-1}$,那么 $(i,a_{i}+2)$ 一定被问过了。

此时,如果 $a_i\neq b_i$,那么我们就利用上了 $(i,a_i+2)$ 的信息,询问次数 $-1$;而如果 $a_i = b_i$,那么 $b_i$ 中一定不会出现 $a_i+1$ 这个数,询问次数 $-1$。

综上,我们一定少询问了 $|\{a_i\}|$ 次,也就是说我们只会询问 $5n/2$ 次。所以总询问次数不会超过 $T(n,n) = T(n/2,n/2) + 5n/2$,即 $T(n,n) = 5n$。

D2T3

idea,solution,data,std by Kubic

$O(n\log^2 n)$

分治。处理所有跨过分治点的贡献。只需 $O(\log n)$ 代价即可转化到原问题。

离线,扫描值域。令当前扫描到 $x$。对于每个 $i$,维护 $p_i$ 表示第 $i$ 时刻分治中心左边距离中心最近的 $\le x$ 的数的距离,$q_i$ 表示右边的距离。

$x$ 增大时对 $p,q$ 的修改均为区间取 $\min$,用 $\text{segbeats}$ 维护即可。

还需要维护每个时刻的答案 $w_i$。第 $i$ 时刻 $\min\ge x$ 的区间数量即为 $p_i\times q_i$。因此 $x$ 增大时,需要令 $w_i\leftarrow w_i+p_i\times q_i$。

每个 $i$ 处维护四维向量 $(p_i,q_i,p_i\times q_i,w_i)$,用矩阵表示修改即可。时间复杂度为 $O(n\log n)$。

加上外层分治,总时间复杂度为 $O(n\log^2 n)$。

$O(n\sqrt n)$

可以把要求的东西转化为 $\sum\limits_{i=1}^n(suf_i-i)(i-pre_i)a_i$。

其中 $pre_i$ 表示 $i$ 前面第一个 $< a_i$ 的位置,$suf_i$ 表示 $i$ 后面第一个 $\le a_i$ 的位置。

考虑询问分块,将 $B$ 个询问分入同一个块中。

在进入每个块之前先将这个块中所涉及到的 $B$ 个位置设为 $+\infty$,然后计算 $pre$ 和 $suf$。

此时序列被这 $B$ 个位置分为了 $O(B)$ 段。

对于一个询问,我们分析填上这 $B$ 个位置的数对 $pre$ 和 $suf$ 的影响。只考虑 $pre$,$suf$ 的分析是类似的。

可能有一些 $pre$ 会变为这 $B$ 个位置之一。每个段内只有所有非严格前缀最小值的 $pre$ 可能改变。

我们用类似于求 $pre$ 的过程,对这 $B$ 个位置以及每个段内的最小值做单调栈。

到达一个段时,我们可以用当前的单调栈刻画出这个段中所有数的 $pre$ 的变化情况:对于一个当前段中的前缀最小值 $a_i$,我们找到单调栈中第一个 $< a_i$ 的数 $a_t$。如果 $t$ 是 $B$ 个位置之一,那么 $pre_i$ 会变为 $t$,否则 $pre_i$ 不变。

于是我们可以把一次询问转化为在序列上的 $O(B^2)$ 次询问,每次询问一个段中有多少个 $\le w$ 的数。

这样做的时间复杂度为 $O(\dfrac{n^2}{B}+nB^2)$,取 $B=n^{\frac{1}{3}}$ 可以得到 $O(n^{\frac{5}{3}})$ 的时间复杂度。

但我们可以进一步优化,可以发现,单调栈中有很多不变的数,我们可以在单调栈改变的时候将后面的数因为这次改变所产生的贡献全部计算出来。每次询问形如在第 $x$ 个段及之后的所有数中有多少个 $\le w$ 的数。

因为段只有 $O(B)$ 个,并且询问的 $w$ 也只有 $O(B)$ 种,所以我们可以用在每个段内双指针,并用二维前缀和预处理出每一种可能的询问的答案。

这 $O(B)$ 个点的贡献容易在过程中同时进行计算,这里不再赘述。

这样做的时间复杂度为 $O(\dfrac{n^2}{B}+nB)$,取 $B=n^{\frac{1}{2}}$ 可以得到 $O(n\sqrt n)$ 的时间复杂度。

UOJ NOI Round #8 Day1 题解

2024-07-13 20:36:57 By zhoukangyang

D1T1

idea,sol,data,std from kubic

别急。

D1T2

idea from cmk666,solution from zjy0001。

记区间 $[l,r]$ 中颜色 $i$ 出现 $c_i(c_i>0)$ 次,如果 $i$ 只出现在 $S$ 中,那么有 $1$ 种选择方法,如果只出现在 $U/S$ 中,那么有 $1$ 种选择方法,否则有 $2^{c_i}-2$ 种选择方法。

考虑构造形式幂级数 $F_i(x)=(x-1)^2+2^{c_i}x,F(x)=\prod_i F_i(x)$ ,如果有 $K$ 种不同的颜色在区间 $[l,r]$ 中出现,那么答案就是 $[x^K]F(x)$。

考虑记 $y=(x-1)^2$ 那么 $F(x)$ 每一项的指数和是固定的 $K$,于是我们可以设 $G_i(x)=1+2^{c_i}x$,求出 $G(x)=\prod_i G_i(x)$,那么答案就是 $[x^K]\sum_i(x-1)^{2(K-i)}x^i[x^i]G(x)=\sum_i(-1)^{K-i}\binom{2(K-i)}{K-i}[x^i]G(x)$。

接下来观察模数的性质,因为$G_i(x)=1+2^{c_i}x,c_i>0$,所以有 $\forall i\ge 64,[x^i]G(x)\equiv 0\pmod{2^{64}}$,于是我们只需要求出 $G$ 的前 $64$ 项即可。

对于 $c_i\ge 64$,我们不用关心,因为 $G_i(x)\equiv 1\pmod{2^{64}}$,对 $G$ 的求解没有影响。

否则,对于 $1\le k\le 63$,依次统计出 $d_k=\sum_i[c_i=k]$,于是 $G(x)=\prod_{k=1}^{63} (1+2^kx)^{d_k}$,容易用组合数预处理出 $(1+2^kx)^{d_k}$ 的每一项系数,并且对于每一个 $k$,其只有前 $\lfloor \dfrac{63}{k}\rfloor$ 的值在模意义下不为 $0$,如果我们从大到小依次枚举 $k$ 乘起来,它依然保持这个性质,于是单次计算 $G(x)$ 的复杂度就是 $\Theta(\log^2 P)$ 的了。

如果用扫描线配合树状数组求出 $d_k$,那么总时间复杂度就是 $\Theta((n+q)\log n\log P+q\log^2 P)$ 的。

D1T3

idea,data,std from unputdownable, solution from unputdownable,zhoukangyang

$n \le 2$

一个点只有两个出边。

如果两者字符不一样,那么直接走对应字符的出边就行。

难处理的是两条出边字符相等的情况。

但是 $n \leq 2$,注意到向右走一定不劣,所以贪心先匹配第一行,然后再往第二行匹配即可。

总复杂度 $O(L+nm+q\log m)$,也可以做到单组查询 $O(1)$。

$n \leq 3$

贪心失效了!真的失效了吗?

考虑我们的贪心什么时候会挂。 $$ S=\text{xxxxxxxxxxxxxxxxxxxxx}\\ \\ \begin{aligned} T=\ &\color{red}\texttt{xxxxxxxxxxxx}\color{black}\texttt{aaaaa}\\ &\color{blue}\texttt{aaaax}\color{black}\texttt{aaaaaaaaaaaa}\\ &\texttt{aaaa}\color{blue}\texttt{xxxxxxxxxxx}\color{black}\texttt{aa}\\ \end{aligned} $$ 考虑选择一个位置提前往下拐。

注意到如果在蓝色分支之前就往下拐,一定不比蓝色优,否则蓝色一定能接到那个路径上去。

所以应该选择最后一个能往下拐的位置往下拐,然后就是 $n=2$ 的部分了。

注意到能往下拐的位置一定满足 $T_{2,x}=T_{1,x+1}$,或者在末尾,而这个是好维护的

记得在两种贪心中取较大的一个。

总复杂度仍是 $O(L+nm+q\log m)$,也可以做到单组查询 $O(1)$。

$n \leq 4$

贪心还有救吗? $$ S=\text{xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx}\\ \\ \begin{aligned} T=\ &\color{red}\texttt{xxxxxxxxxxxxxxxxxx}\color{}\texttt{aaaaaa}\\ &\texttt{a}\color{green}\texttt{x}\color{}\texttt{aa}\color{blue}\texttt{x}\color{}\texttt{a}\color{blue}\texttt{x}\color{}\texttt{a}\color{blue}\texttt{x}\color{}\texttt{a}\color{blue}\texttt{x}\color{}\texttt{a}\color{blue}\texttt{x}\color{}\texttt{a}\color{blue}\texttt{x}\color{}\texttt{a}\color{blue}\texttt{x}\color{black}\texttt{aaaaaaa}\\ &\texttt{a}\color{green}\texttt{x}\color{}\texttt{aaaaaaaaaaaaaaaaaaaaaa}\\ &\texttt{a}\color{green}\texttt{xxxxxxxxxxxxxxxxxxxxxxx}\\ \end{aligned} $$

这样子可以把上述贪心卡死。

但是如果能找到一个直达第三排的位置,从那个位置往下拐贪一下,就还有救。

因为考虑所有从第二行转移到第三行的列,如果这一列的第一行无法到达,那么可以被走完第一行再接 $n=3$ 的贪心;

而当我们找到一个能直达第三行的位置,和 $n=3$ 的情况就差不多了,可以证明这是最优的决策之一。

观察到能到第三排的位置应该满足 $T_{2,x}=T_{1,x+1},T_{3,x}=T_{1,x+2}$;或者 $x$ 在第一行贪心匹配部分(上图红色)末尾两个字符(需要特判)。

将走完第一行再接 $n=3$;第一行走到剩下一个再接 $n=3$;选择最后一个能往下拐的位置往下拐;找到最后一个能直达第三行的位置往下拐四种贪心拼起来即可通过 $n=4$。

总复杂度仍是 $O(L+nm+q\log m)$,也可以做到单组查询 $O(1)$。

$L,m,q \leq 1000$

对于询问暴力跑一个朴素的 DP,记 $f_{i,j}$ 表示能否走到 $(i,j)$ 这个点,单次询问复杂度 $O(nm)$,

总复杂度 $O(L+nm+qnm)$。

$L,m,q \leq 10^4$

注意到 DP 状态只有 $01$,直接压位用位运算做 DP,单组询问复杂度 $O(m)$;

总复杂度 $O(L+nm\sum+qm)$。

$n \leq 7$

贪心彻底没救了,因为此时路径的形态会变得相当复杂。

注意到 $n$ 很小,考虑想办法维护上述动态 DP。

首先将矩阵转换为斜矩阵以方便理解(第 $i$ 行向右平移 $i-1$ 个字符),这样每一步是向右或者向右下走,即第 $i$ 步一定走到第 $i$ 列。

维护 DP,第 $i$ 列的状态只和第 $i-1$ 列的状态以及需要匹配的字符有关。

难点在于转移矩阵会随着询问的字符串而改变。

想办法固定每个位置的转移矩阵。

注意到如果先贪心在第一行匹配,那么在和第一行匹配上的这个区间内,转移矩阵是固定的。

直接动态 DP 维护此时的 DP 状态;如果下面的行已经没有可达的位置了,那么贪心匹配第一行一定是最优的;否则跳到下方第一个可以到达的行,然后递归。

预处理动态 DP 矩阵,查询时只需要做至多 $n$ 遍向量乘区间的转移矩阵。

视实现的不同复杂度大约 $O(L \log L+n^3m\log m+qn^3)$。

$n \leq 10$

注意到矩阵很小,可以压位,单次矩乘 $O(n^2)$。

上猫树,注意到每次乘的是单个转移矩阵,而不是若干转移矩阵的积,其中非 $0$ 元素只有 $O(n)$ 个。

这样预处理时单次矩乘 $O(n)$。

复杂度 $O(L \log L+n^2m \log m+qn^2)$。

由于实测时间瓶颈在 $SA$ 预处理上,所以即使你的询问多一个 $n$ 或者多一只 $\log$,如果卡常较为精细也能通过。

谢罪

部分乱搞获得了 $84$,复杂度错误的 $O(m2^{\frac n 2})$ 以及 $O(m2^n)$ 也通过了。

UOJ NOI Round #8 公告

2024-07-02 22:50:14 By zhoukangyang

转眼间又是一年 NOI 了,为了帮大家备战 NOI,延续 UOJ 的传统保留项目,UOJ NOI Round #8 将在 7 月 12 号到 7 月 14 号隆重举行!

为了方便阅读,同时也因为管理员比较鸽,这次的 UNR 没有特别的主题。

比赛时间

笔试模拟将于 7 月 12 日晚 19 点开始,将进行半个小时。

Day 1 的比赛将于 7 月 13 日上午 8 点半开始,将进行五个小时,共三道题。

Day 2 的比赛将于 7 月 14 日上午 8 点半开始,将进行五个小时,共三道题。

比赛难度

比赛的难度将和 NOI2023 相近,相信对绝大部分选手来说题目是具有一定的挑战性的。

题目中可能拥有若干道非传统题(可能包括但不限于交互题、提交答案题、通信题),大家可以放心食用。

出题阵容

拯救这一年度的 UNR 的出题人将在稍后公布。各位可以先行无奖竞猜出题人的名单。

这场比赛除笔试外将计入 rating。

比赛奖项

这次比赛将会根据三次比赛的总分进行排序(如果存在同分将以两天的罚时总和作为第二关键字),其中比赛的前三十名将成为这次训练的金牌得主,第三十一名到第一百二十名将获得银牌,第一百二十一名到第二百名将获得铜牌。(得奖人数将根据参赛人数进行调整)

总分前三名将获得 UOJ 萌萌哒的撕烤熊抱枕一只。

UOJ Round #27 题解

2024-05-13 08:15:16 By zhoukangyang

景点观光

idea, data, solution, std from Ecrade_

引理 1:不移动到子树内没有黑点的结点一定不劣。

我们的目标是遍历到所有黑点,而移动到子树内没有黑点的结点只会徒增操作次数。

引理 2:当移动到结点 $u$ 的子树内时,遍历完 $u$ 子树内的所有黑点再移动到 $u$ 的子树外一定不劣。

若未遍历完 $u$ 子树内的所有黑点就移动到了 $u$ 的子树外,则后面仍需再次移动到 $u$ 子树内遍历剩下的黑点,而这显然只会徒增操作次数。

引理 3:去除子树内没有黑点的结点后得到一棵新树,那么沿着新树的某种欧拉序移动一定不劣。

不妨令红点表示当前未遍历完子树内所有黑点的结点,绿点反之。

根据引理 1,去除子树内没有黑点的结点不会造成任何影响。

根据引理 2,若当前棋子在红点处,则棋子只能往下移动(即移动到深度更大的结点处)。

若当前棋子在绿点 $u$ 处,则考虑离 $u$ 最近且为红点的祖先结点 $r$。

根据引理 2,棋子接下来只能移动到 $r$ 子树内的某个黑点。

观察到在移动的过程中,棋子必然会经过 $r$ 或 $r$ 的某个子结点。

那么在从 $u$ 移动到 $r$ 或 $r$ 的某个子结点的过程中,由于路径上除了 $r$ 为红点,其余均为绿点,故一直往上移动是最优的。

接着,在到达 $r$ 或 $r$ 的某个子结点后,棋子必然又在红点处,这时只能往下移动了。

移动到最后一个黑点后,显然我们一直往上移动至根节点即可。

所以,在整个过程中,我们发现棋子是不会走“回头路”的,其实这也是沿着欧拉序移动的充要条件。

引理 4:沿着新树的欧拉序移动一定是所有移动路径中总路程最短的。

显然,我们必须要经过所有新树的叶结点。

所以,每条边都需要被经过至少两次,而沿着欧拉序移动恰能达到这个理论下界。


注意到总路程 $l$ 为定值(新树边数的两倍),若第二种操作进行了 $x$ 次,则总操作次数为 $x+(l-2x)=l-x$。

所以,我们仅需知道 $x$ 在无限制的情况下的最大值 $x_{\text{max}}$ 即可,这样对于每个询问,答案即为 $l-\min(k,x_{\text{max}})$。

考虑使用动态规划计算出 $x$ 取到最大值时的操作次数。

定义 $f_{u,0/1,0/1}$ 表示进入结点 $u$ 的子树内时,棋子处在 $u/u$ 的某个子结点处;遍历完 $u$ 子树内所有黑点后,将要从 $u/u$ 的某个子结点移动到 $u$ 子树外的操作次数。

由于 $f_{u,0,1}$ 和 $f_{u,1,0}$ 的情况是对称的,故我们仅考虑 $f_{u,1,0}$。

对于 $u$ 的所有子结点,我们需找到一个合适的遍历顺序,使得依次拼接后操作次数最少。

容易发现,相邻两个子结点分别是 $0$ 出和 $0$ 进时,则中间只需进行一次操作,而其余情况则需进行两次操作,故一个直观的想法是 $0$ 越多越好。

考虑贪心。

一般情况下,当 $f_{v,0,0}\le f_{v,0,1}$ 时,取 $f_{v,0,0}$ 不劣。

一般情况下,当 $f_{v,0,0}>f_{v,0,1}$ 时,取 $f_{v,0,1}$ 不劣。

$f_{v,0,1}$ 和 $f_{v,1,1}$ 同理。

所以我们得出结论:一般情况下,对于 $f_{v,0,0},f_{v,0,1},f_{v,1,0}$,哪个最小就取哪个,若有多个最小值,则哪个含 $0$ 越多就取哪个。

至于这里的结论为什么只适用于一般情况下,后续会提及。

子结点与子结点之间的拼接情况已处理完,最后仅剩下首尾两处根结点与子结点之间的情况了。

显然,当根结点 $u$ 和子结点 $v$ 分别满足 $1$ 进和 $0$ 进或是 $1$ 出和 $0$ 出,即进/出 $u$ 子树时处在的结点恰为 $v$ 时,便不需要进行操作,而其余情况则需进行一次操作。

仍考虑贪心。

  • 当 $u$ 满足 $0$ 进 $0$ 出时:

首尾两处与子结点均需进行一次操作,而中间相邻子结点之间分别满足 $0$ 出和 $0$ 进的数量越多越好。

当没有 $0$ 进 $1$ 出或 $1$ 进 $0$ 出的子结点时,只能将所有 $0$ 进 $0$ 出的子结点紧挨着排,后跟着所有 $1$ 进 $1$ 出的子结点;

否则将一个 $1$ 进 $0$ 出的子结点排在首位,后跟着所有 $0$ 进 $0$ 出的子结点,再跟着 $0$ 进 $1$ 出、 $1$ 进 $0$ 出的交替排列,最后跟着所有 $1$ 进 $1$ 出的子结点。

  • 当 $u$ 满足 $1$ 进 $0$ 出时:

将所有 $0$ 进 $0$ 出的子结点紧挨着排,后跟着 $0$ 进 $1$ 出、 $1$ 进 $0$ 出的交替排列,最后跟着所有 $1$ 进 $1$ 出的子结点。

  • 当 $u$ 满足 $1$ 进 $1$ 出时:

若 $u$ 仅有一个子结点,暴力考虑所有情况即可;

否则将所有 $0$ 出 $0$ 进的子结点紧挨着排,后跟着 $0$ 出 $1$ 进、 $1$ 出 $0$ 进的交替排列,再后跟着所有 $1$ 出 $1$ 进的子结点,最后跟一个 $1$ 出 $0$ 进的的子结点。

注意这里需要再考虑强制将所有子结点变为 $0$ 进 $0$ 出的子结点的情况,因为这时的贪心可能就不奏效了。注意此时若 $u$ 为黑点则需中途再进行一次操作去遍历 $u$。

至此,我们便用 $O(\sum n+\sum q)$ 时间复杂度解决了本题。

509 号迷宫

idea, data, solution, std from JohnVictor

算法一(暴力)

直接 $\text{DP}$,复杂度 $O(n^2)$,可以通过第一个子任务。

算法二(部分分)

输出 $0$ 可以通过第二个子任务。第三个子任务的答案可以用一些组合数简单表示。对于第四个子任务,可以看做 $O(np)$ 个点加一个下三角,下三角部分的贡献可以简单反射容斥计算,剩下部分暴力即可。第五个子任务留给小常数 $O(n\sqrt {n \log n})$ 的直接分块 $\text{NTT}$ 和大常数正解。

算法三(正解)

下面的分析中,令块长 $B=p$。

考虑平移指数基。具体地,对于每一列,考虑维护一个形如 $P(x)/(1-x)^k$ 的多项式表示一整列的 $\text{DP}$ 值构成的生成函数。

我们要支持的操作是加一个单项式,查询一项系数(这两个操作足以解决每一列有一个不能走的点的问题),将 $k$ 加上 $1$(也就是一次前缀和)。

考虑定期重构。我们维护 $P(x)(1-x)^k$ 的形式。每一次将 $k$ 减小 $1$,变成了 $0$ 就重构。这样,对于这个形式查询一项系数是 $O(B)$ 的。

利用 $1-x^p=(1-x)^p$,重构的时候只用除以 $(1-x^B)$,这个相当于隔 $B$ 个做一次前缀和,复杂度 $O(n)$。

主要的问题是加一个单项式之后再除以 $(1-x)$ 怎么办。这个只用额外维护成 $P(x)(1-x)^k+Q(x)/(1-x)^k$ 即可。注意这里的系数还是可以 $O(k)$ 来计算的,因为 $Q$ 不超过 $k$ 个非零系数,单个贡献可以 $O(1)$。

所以现在的复杂度为 $\mathcal O(np+\frac {n^2}{p})$,可以通过所有子任务。

算法四

考虑每 $p$ 条斜线(即 $i+j=t\times p$ 的位置 $(i,j)$)算一次 dp 值。转移的时候可以考虑对障碍点容斥,钦定一些障碍点被经过了,并对可能产生转移的两个障碍点之间计算贡献。

斜线 -> 斜线的贡献可以 $\mathcal O(\frac{n^2}{p})$ 处理;障碍点 -> 障碍点,斜线 -> 障碍点和 障碍点 -> 斜线的贡献均可以 $\mathcal O(np)$ 处理。

时间复杂度 $\mathcal O(np+\frac {n^2}{p})$。

红场阅兵

idea, data, solution, std from zhoukangyang. sol-114514,-1919810 from bulijiojiodibulido

APIO2024 会讲的。大家可以提前复习一下积性函数相关知识。UPD:apio 讲课的核心内容放在了 这里

算法 -114514,-1919810 是 bulijiojiodibulido 老师验题时用的做法,算法一、算法二是官方题解做法。

算法 -114514

令 $t=\gcd(i, j)$,如果我们提取 $i$ 和 $j$ 中与 $t$ 相关的所有因子,即令 $i = t_is_i, j =t_js_j$,其中 $\gcd(t_i, s) = \gcd(t_j, s) = 1$。那么有 $f(ij) = f(s_i) f(s_j) f(t_i t_j)$。

所以可以考虑枚举 $t_i, t_j$,满足它们有相同的素因子分布(即 $\text{rad}(t) = \text{rad}(t_i) = \text{rad} (t_j)$,其中 $\text{rad}(n) = \prod_{p|n} p$),然后计算上式。这个时候我们还有 $\gcd(s_i, t) = \gcd(s_j, t) = 1$ 的条件,如果直接反演,那么复杂度比较高。

类似构造系数 $g(y_i, y_j)$,满足 $\sum_{x_i|y_i, x_j | y_j, \text{rad} (x_i) = \text{rad} (x_j)} g(x_i, x_j) = f(x_ix_j)$。令 $F(n) = \sum_{i=1}^n f(i)$。那么答案为 $$\sum_{t_i,t_j ,\text{rad}(t_i) = \text{rad} (t_j)} g(t_i, t_j) F(\lfloor{n/t_i\rfloor}) F(\lfloor{n/t_j\rfloor})$$。因为我们能保证每对 $t_i, t_j$,前面加的总系数为 $f(t_i t_j)$。

对于函数 $g$,在上面等式中,右侧是积性,也就是关于每个素因子是独立的,所以 $g$ 的取值也是对于每个素因子都是独立的。所以只需要对于所有素数,预处理出 $g(p^i, p^j)$ 的值(事实上是一个次数为 $2(i+j)$ 的多项式),那么对于任意两个数,可以快速算出上述的 $g$ 值。

这个时候直接枚举 $t_i, t_j$,也就是从小到大枚举每个素数,以及在 $t_i, t_j$ 中的指数就能快速计算答案。枚举代价为 $1$ 到 $n$ 内所有 $\text{rad}$ 相同的数字的对数,好像是 $O(n)$ 级别的,可以通过 $3\times 10^7$ 的数据。

算法 -1919810

考虑如何加速这个过程,我们希望能快速计算出比较大的素数的贡献。

$dp_{n_1, n_2, p}$ 表示从大到小枚举因子到 $p$,$n_1 = \lfloor{n/t_i\rfloor}, n_2 = \lfloor{n/t_j\rfloor}$,$g$ 的乘积。对于大于 $\sqrt{n}$ 的素数,它一定是从 $(n, n)$ 转移向 $(\lfloor n/p \rfloor, \lfloor n/p \rfloor)$,并且乘上的是一个四次多项式。

那么我们只需要预处理 $\lfloor n/p \rfloor$ 相同的每段的素数的四次多项式的值,就可以快速完成这些素数的转移。对于剩下的素数,我们枚举它们的指数,从大到小转移即可。

如果使用记忆化,当 $n=10^9$ 的时候,状态数大概在 $2\times 10^6$ 级别,转移大概在 $2\times 10^8$ 级别,使用精细的实现卡常数就可以通过。

实际大部分的状态都是在小素数的地方,所以可能可以从小素数枚举然后 meet in the middle,但是没编出来。

算法一

考虑把积性函数推广至二维,如果函数 $f(x,y)$ 是二维积性函数,假设 $p_i$ 是从小到大第 $i$ 个质数,$x=\prod_i p_i^{a_i}$,$y=\prod_i p_i^{b_i}$,那么 $f(x,y) = \prod_{i} f(p_i^{a_i},p_i^{b_i})$。容易发现我们要求的是二维积性函数前缀和。

考虑设计积性函数 $g(x,y)$ 满足 $g(p^{a},p^b) = f(p^a,1) f(1,p^b)$。对于这个函数,其前缀和 $\sum_{i\le n_1} \sum_{j\le n_2} f(i,1)f(1,j)$ 是相当容易计算的。观察 $h=f/g$。我们发现 $h(p^k,1) = h(1,p^k) = 0$。

暴力枚举 $h$ 有值的位置,可以证明复杂度是 $\mathcal O(n)$。期望得分 $70$ 分。

算法二

考虑优化之前的算法,设计二维积性函数 $g_3$ 满足 $g_3$ 只在 $g_3(x,x)$ 处有值且值为 $h(x,x)$,接下来令 $h' = h/g_3$。

此时有值的 $h'(p^a,p^b)$($p\in \mathbb{P}, a,b\ge 0$,$a+b\neq 0$)就满足 $a,b\ge 1$ 且 $a\neq b$ 了。

接下来暴力枚举 $h'$ 中的有值元素 $(x,y)$,计算 $\sum_{u \le n/x,v\le n/y} (g * g_3) (u,v)$,把这些答案带上系数加起来就能得到最终答案了。

而 $\sum_{i=1}^A \sum_{j=1}^{B} (g * g_3)(u,v) = \sum_{k=1}^{\min(A,B)} g_3(k,k) \sum_{i=1}^{A/k}\sum_{j=1}^{B/k} g(i,j)$。暴力整出分块计算答案。

我们当然要筛 $f(x,1)$ 和 $g_3(x,x)$ 的块筛前缀和。可以证明,除此之外的复杂度不超过 $\mathcal O(n^{2/3}\log n)$。

其实还可以更快一点,不过没必要了。

zhoukangyang Avatar