Cry_For_theMoon  

1. Split and Maximize

场上没写出这个题,多少有些菜了。

首先研究如何最大化答案,肯定是 \(1\times 2 + 3\times 4 + 5\times 6\) 这样配对。显然这是唯一最大化答案的方式。

所以我们求的是能这样划分的排列 \(P\)

对于一组要在一起乘的 \((x,y)\),我们假设 \(x\)\(y\) 的左边,那么对于 \(n\) 对去决策,就有 \(2^n\) 种可能。

然后我们要把这 \(n\) 对组合在一起。首先忽略 \(y\)\(x\) 的排列方式有 \(n!\) 种。对于每种排列方式,我们再把所有的 \(y\) 加入。

我们发现只要任意前缀,\(x\) 的个数不少于 \(y\) 的个数就能一定划分出来,反之肯定划分不出来,所以等价于卡特兰数。

那么这个问题就做完了(可能需要了解卡特兰数的封闭形式)。

记录

2. Grammar

考虑如果没有死循环的情况:如果 \(a\) 的展开式有 \(b\),那么连 \(a\rightarrow b\) 的边。对这个 dag 拓扑地 dp,很容易算出每个串最后的长度。

然后我们考虑一个 \(dfs(u,x)\),表示询问串 \(u\) 的第 \(x\) 位,对于所有 \(u\rightarrow v\),按照输入给出的顺序排序,然后因为你知道了每个展开串的长度,也知道每个串中间隔的字符数量,可以通过简单二分,变成一个子问题:询问串 \(v\) 的第 \(y\) 位。因为没有死循环,所以一次询问最多进入一个点一次,那么单次复杂度的上界是 \(O(n\log n)\) 的。

考虑如果会死循环,就把长度设为 \(\infty\)(本题中可以视为 \(2\times 10^{18}\))。然后重复这样的过程。但是我们不能保证一个点只被访问一次了。

考虑如果是第一次访问一个已经经过了的点 \(u\),如果第一次查的是它的第 \(y\) 位,第二次查的是它的 \(y'\) 位,则设 \(d=y-y'\),那么你下次如果还能回到 \(u\),显然有 \(y''=y'-d\),所以我们可以把现在的 \(y'\)\(d\) 取模(特判是 \(d\) 的倍数的情况),然后就保证了不会第三次回到 \(u\)。这样,一个点至多被访问两次,时间复杂度仍然是 \(O(n\log n)\)

这次 HDU 不卡我常数了,暖心的。

P.S. 突然发现这样似乎并不能保证一个点至多访问两次,但是我们如果走了一个环,让 \(y\) 减小了 \(a\),那么可以视作 \(y=(y-a)\bmod a\)

然后感性理解一下,这样操作,过不了多少次,就会让 \(y\) 到达和 \(n\) 同阶的级别,所以可以视作 \(O(n\log n)\)

感觉这次没问题了

UPD:后来研究了一下发现卡死好像是每个点访问 \(\log n\) 次,但这个次数实际上非常极限...... 也可能是数据比较水了,乐。

记录

3. Jo loves counting

PN 筛的基础题。

可以把 \(\frac{1}{M}\) 提出来,然后就变成了:\(\sum_{i=1}^{n} \frac{i}{d(\frac{i}{base_i})}\),其中 \(d\) 代表约数个数,而 \(base_i\) 就是 \(i\) 的所有本质不同质因子的乘积。

看上去有了 \(base_i\) 变得麻烦了,其实是简化了:我们知道约数个数是指数 \(+1\) 后的乘积,而除去 \(base_i\) 后,实际上约数个数是 \(i\) 分解质因数后,指数的乘积。

即设 \(i=\prod p_j^{a_j}\),则变成了求 \(\sum_{i=1}^{n}\frac{i}{\prod a_j}\)

首先设 \(f(n)=\frac{n}{\prod a_j}\),那么 \(f\) 是积性函数,这是容易的。所以问题实质上是求一个积性函数的前缀和。

PN 筛会出现在这样的场合:求积性函数 \(f\) 的前缀和(通常是单个点值)。存在一个积性函数 \(g\),对于所有质数 \(p\) 满足 \(g(p)=f(p)\),且 \(g\) 的前缀和函数 \(G\) 是容易求的(要么有 \(O(1)\) 的式子,要么往往可以利用杜教筛求得)。如果需要利用杜教筛求 \(G\),则可以在 \(O(n^{2/3})\) 的时间内求 \(F(n)\),否则如果是 \(O(1)\)\(G\),就可以在 \(O(n^{1/2})\) 的时间内求 \(F(n)\)

如果能找到这样一个函数 \(g\),我们就要构造一个积性函数 \(h\),使得它们的狄利克雷卷积为 \(f\)。当然直接构造是没有出路的,但是我们知道 \(f\)\(g\),就可以反推 \(h\)\(p^c\) 处的取值。再利用积性函数来求 \(h\),更重要的一点是:因为 \(f(p)=g(p)\),所以 \(h(p)=0\),也就是说,如果 \(h(x)\) 不为 \(0\),则必须满足 \(x\) 的每个质因子都出现了 \(2\) 次及以上。这样的数被称作 powerful number(PN),我们发现所有 PN 可以写成 \(a^2b^3\) 的形式(包括 \(1\) 也是 PN)。一个结论是 \(N\) 以内的 PN 个数是 \(O(N^{\frac{1}{2}})\) 级别的,这个结论可以把离散和式转为连续求和(积分)来加以证明。

然后有:

\[F(n)=\sum_{i=1}^{n}\sum_{d\mid i}h(d)g(\frac{i}{d})=\sum_{i=1}^{n}h(i)G(\lfloor \frac{n}{i} \rfloor) \]

又因为 \(h(i)\) 不为 \(0\)\(i\) 最多有 \(O(\sqrt n)\) 个,所以整个复杂度是 \(O(\sqrt n)\) 的,在本题就是 \(O(\sqrt M)\) 的。

本题的模数比较厉害...... 如果开 __int128 会方便很多,我手写了龟速乘不出所料刚开始还被卡了一发常数...

记录

4. Spanning Tree Game

这个做法不同于现有的做法,其实是我赛场口胡的,当时得到了 TLE,赛后队友竟然直接跑过去了,令我大为震惊。

考虑设 \(f(mask,i)\) 是集合 \(mask\) 连通,且让 \(i\) 条边设了属性 \(a\),此时这个集合的 MST 的最大值。

怎么转移?枚举 \(mask\) 的一个子集 \(S\),其在 \(mask\) 中的补集设为 \(T\),那么我们假设 \(S\)\(T\) 各自连通,最后钦定一条边连接这两个部分。你会发现,根据生成树的特性,设我们钦定的这条边边权为 \(w\),那么其它跨越两部分的边权要 \(\ge w\),且两个子集内部的生成树,最大边权不能超过 \(w\)。所以我们考虑给 dp 状态加一维:\(f(mask,i,j)\) 表示 \(mask\) 连通,其中 \(i\) 条边设了属性 \(a\),MST 的边权全部 \(\le j\),此时 MST 的最大值。

观察到有意义的 \(j\) 不超过 \(2\times M\) 个,所以共有 \(2^n\times m^2\) 个状态。转移是容易的,但是复杂度高达 \(O(3^n \times m^4)\)

虽然这个转移明显跑不满,但是能在赛后 HDU 的机子上依然只跑了 5s,这是我没想到了。

记录

5. Range Reachability Query

是一个本身思想很巧妙的题,但是 HDU + DS......

首先需要知道的是就算我们去掉区间询问的限制,也不可能在低于平方的时间内求出任意两点可达性这个问题。所以如果去掉区间询问,也只能用 bitset 加速暴力的过程。

所以本题在一个困难的问题基础上还加了区间询问的限制,看上去就很吓人。那么我们依旧要考虑 bitset 来处理。经过尝试后会发现常规处理区间的手段很多都会失效,因为 dag 两点可达性的性质太差了。比如你如果试图使用回滚莫队然后变成一边加入边,一边询问可达性,你会发现也是做不了的。

所以我们试图把询问压入 bitset 的状态:设 \(f(u,i)\)\(u\) 能否通过第 \(i\) 次询问的边走到 \(y_i\)。那么 \(f(x_i,i)\) 就是答案。

如果我们想计算 \(f\),会发现还要计算一个 \(e(i,j)\) 表示第 \(i\) 条边是否处于第 \(j\) 次询问中。\(e\) 的处理可以通过离线,然后把 \(l,r\) 拆成两个差分 tag 来处理。

但是这样空间复杂度会不够..... 一般这个时候都是考虑分块来优化空间,因为你都上了 bitset 了,很少有其它高妙手段了。本题中优化空间的手段是分块:考虑那个把 \(l,r\) 拆成差分 tag 的东西,然后你要求 \(m\) 个前缀和。所以我们考虑每隔 \(\sqrt{m}\) 个存一次前缀和,这样你询问一个前缀和的话再用不超过 \(\sqrt m\) 次的时间暴力一下就行。

只能说 DS 题赛后补起来卡这个 HDU 傻逼机子太痛苦了,最后从 std 那里把手写 bitset 复制了一份才过......

记录

6. Berland Miners

一个劣很多的做法。

考虑把人和洞按照值降序排序,这样你就可以简单地处理 check 了。

修改一个点,只会影响一个连通块,且根是你修改的点。把所有的连通块划分预处理出来。二分答案后枚举修改的是哪个点,再把这个连通块里的所有点取出来,设有 \(N\) 个,那么就相当于修改了 \(N\) 个数。修改可以视作删除,再往前插入(因为只会往大了改,所以位置只会往前)。

对于第 \(i\) 个人设 \(f(i)\) 是排序后最后面的那个 \(\ge s_i\) 的洞,那么要求是所有的 \(i-f(i)\) 非正。

然后一次修改就可以视作把一个区间的 \(i-f(i)\) 的值减一。如果你把 \(2\times N\) 个差分 tag 全部算出来后排序,相同位置的合并,那么就变成了不超过 \(2\times K+1\) 次的区间求 \(i-f(i)\) 的最大值。直接 st 表预处理即可。

注意到每次算修改的区间实质上是需要两次二分的;观察到这个连通块其实有一些单调性:若 \(u\)\(v\) 的祖先那么原本的值,\(u\) 会大一些,最后取值的上界,\(u\) 也会大一些。如果你第一关键字按照每个洞最初的值,第二关键字按照拓扑序之类的去把连通块内的洞排序,你就会发现右边界的值可以通过双指针预处理,这样就砍掉了不小的常数。卡一卡 \(O(n\log n\log w)\) 贴着时限就过去了。

(事实上关于差分的排序,我的想法是 \(+1\) 的 tag 和 \(-1\) 的 tag 应该是各自有序的,最后归并一下就行,但是不知道什么原因,这样优化过不去。)

记录

7. Tree Calendar

可能是比较思维的题,感觉手玩一会儿会比较容易,不过很难表述,实现也需要仔细思考,不然会很丑。

考虑肯定是不断移动 \((1,x)\) 直到 \(1\) 到了某个叶子,然后你可以删了 \(1\) 最后在的那个点,重复这个过程,最后会有一个点移了一半就终止移动了。

然后你知道最后的 \(a\),那么就知道确切的移动到了哪个叶子。设路径是 \(1\rightarrow u_2\rightarrow ...\rightarrow u_k\),你发现 \(1\sim u_k\) 这些点的初始 dfs 序其实就是 \(1\sim k\)。然后最后 \(1\) 到了叶子,你发现 \(2\) 本来在 \(1\) 的某个儿子,会被换到根。然后重复这个过程。每次你都是把一个数从根开始往一个确定的位置移动。

所有移动过程中被访问到的点,它的 dfs 序都是确定的。对于没有被遍历过的点 \(u\)\(a_u\) 始终是不会变化的。

这样你就构造出了一组唯一的初始的 \(a'\),问题变为判断合法性。

首先你要知道那个每次的终点是否是合法的。因为你发现根据它字典序最小的过程,任意时刻那些移动完了的节点会沉在最底下,实质上是一个后序遍历的过程;其次,你最后求出来的 \(a'\) 必须满足就是 dfs 序;最后,从 \(a'\) 开始模拟是否真的能变为给出的 \(a\)?因为我们是根据某些确定的位置推出剩余的位置的唯一可能性,那些确定的位置就是满足约束的,而我们推导出的点不一定。事实上设最后的真实序列为 \(a''\),那么 \(a_u''=a_u'+cnt_u\),其中 \(cnt_u\) 是子树中那些确定的点的数目。

发现这个过程可以用 bit 维护,具体有一些细节。时间复杂度 \(O(n\log n)\)

记录

8. The Awesomest Vertex

可能是思路比较容易的题。

本质是区间对 \(a_i\) 加上 \(x\),然后区间询问 \(\max |a_i|\times |b_i|\)

考虑分块,那么散块是容易的。如何处理整块加 \(x\) 这样一个操作?这里我们会发现设块整体的 \(a\) 增加了 \(x\),那么答案关于 \(x\) 是一个下凸壳的形式。

因为你可以把 \(y=k|a_i+x|\) 拆成两条线 \(y=k(a_i+x)\)\(y=-k(a_i+x)\) 然后求 \(\max\),那么变成了若干个一次函数求 \(\max\) 的问题,首先可以想到李超树,发现是根号 log;然后我们考虑去掉 log 就不能使用李超树,就会容易想到直接维护凸壳。

这里有一个技巧,也是我一直用的,就是我们维护若干条直线 \(y=kx+b\) 构成的凸壳,你注意到最后是,\(k,b\) 固定,对于已知的 \(x\)\(\max y\)。我们把式子改写成 \(b=-kx+y\),然后重新替换变量变成 \(y'=k' x' + b'\) 的形式,此时是 \(x',y'\) 固定,对于已知的 \(k'\)\(\max b'\),这样我们把原来的直线视作一个点 \((-k,b)\) 然后变成了斜率优化的那种凸壳形式。注意此时你维护的应该是个上凸壳了。

当然你肯定要把最后的所有点 \((-k,b)\) 按照第一维排序,你发现第一维度 \(|b_i|\) 是永远不变化的,所以散块修改重构凸壳的时候并不需要把点重新排序,这里的 \(\log\) 就没有了;考虑查询的时候还要二分,但是因为每次加的 \(x\) 是正的,所以决策点一定在不断左移,写一个指针维护即可。这样最开始所有指针加起来会移动 \(O(n)\) 次,每次重构一个块会多出 \(O(\sqrt n)\) 的贡献次数,那么总共的移动次数也是 \(O(q\sqrt n)\) 级别的。

所以最后总复杂度是 \(O(q\sqrt n)\),我们发现重构凸壳+指针移动的常数显然是相对来说比较大的,所以我们可以考虑把块长适当调小。

注意如果你维护凸壳的时候是交叉相乘的话,这个过程其实可以被构造出超过有符号 64 位整数的数据,建议过程中使用 __int128

记录

9. Cumulative Cumulative Cumulative Sum

本身其实是个简单题,我主要想谈谈关于单点修改,维护 \(m\) 阶前缀和的事情如何做到 \(O(qm(m+\log n))\) 的复杂度,今天和同学出去联谊了,所以实际上这个东西花费了我一天的时间。

考虑设最后的 \(m\) 阶前缀和序列为 \(S\)。位置 \(a_i\),对位置 \(F_{i+j}\) 的贡献系数为 \(\dbinom{j+m-1}{m-1}\),这是由插板法得出的经典结论。

我们知道这个组合数是关于 \(j\)\(m-1\) 次多项式,通过很多手段,我们可以预处理出这个多项式 \(h(j)\)

所以位置 \(x\) 对位置 \(y(x\le y)\) 的贡献是和它们的差相关的,那么如果你要求 \(F_{y}\),对于所有的 \(x\le y\)\(h(y-x)\times a_x\) 显然都是不能合并的。

考虑对于每个 \(a_x\),把 \(h(j)\) 这个函数向右平移 \(x\) 位得到 \(h'\),那么你会发现 \(h'(j)=h(j-x)\),这样,我们求 \(F_y\),就是对于每个 \(x\le y\),首先得到 \(h'(y)\) 的值,然后把 \(h'(y)\times a_x\) 加进答案。

我们发现:

\[h'(y)=h(y-x)=\sum_{i=0}^{m-1}h_i(y-x)^i=\sum_{i=0}^{m-1}h_i\sum_{j=0}^{i}\dbinom{i}{j}y^j(-x)^{i-j}=\sum_{i=0}^{m-1}y^j\sum_{j=i}^{m-1}\dbinom{j}{i}h_j(-x)^{j-i} \]

你发现这个式子除了 \((-x)^{j-i}\) 这个因式以外,其它的东西都只和 \(y\) 有关:如果我们对于所有的 \(k\),都能维护出 \((-x)^{k}\times a_x\) 的前缀和,那么把结果带入上面的多项式就算完了。这样,就得到了 \(O(qm(m+\log n))\) 的做法。

感觉学会了以后应该还是不难快速手推一遍推得的。

记录

10. Ironforge

其实是质量很高的题,感觉如果没撞 JOISC 的话可能过的没有这么多 2333。

考虑预处理出从每个位置出发最远能走到的区间,首先观察到一定是左右反复横跳的形式,然后我们会感觉这个非常不可做。

如果我们从左往右地计算 \(L,R\)。然后每次暴力地向两边拓展,向左边拓展的时候利用已经有的 \(L\) 的信息来加速,那么我们会自然地想往右边也加速。

我们当然可以预处理一个 \(R'_{i}\) 表示只往右走能走到的最远的点。我们将说明只利用 \(R'\) 来加速转移就可以做到均摊 \(O(n)\) 的复杂度。

考虑如果你跳到了 \(i\),然后你就对 \(i-(i+1)\) 这一段做检查,如果走不过去,那么这样的次数,不超过你左边暴力的次数,可以忽略;否则,说明当前的 \(R_x\ge i\)

然后我们来说明 \(i-(i+1)\) 不会第二次被检查了,只需要考虑到,计算 \(L_i,R_i\) 的时候,如果 \(R_{i-1}\ge i\),那么如果 \(i\) 还能走到 \(i-1\),这两个位置的对应区间是等同的;否则就说明 \(i\) 只能往右走,那么 \(R_i=R'_{i}\)。如果你把这个优化加入计算中,就容易说明 \(i-(i+1)\) 只会被检查一次。

考虑到单次 check 的问题所以时间复杂度是 \(O(n\log n)\) 的。

记录

11. 数字电路

或许是今年 IOI 最简单的一个题?

考虑静态下怎么处理。容易想到树形 dp:设 \(f(u)\) 表示 \(u\)\(1\),其子树的方案数;\(g(u)\) 表示 \(u\)\(0\),其子树的方案数。显然 \(f(u)+g(u)\) 即总方案数是容易预先求出的。所以 \(f,g\) 相当于知一求一:我们最后只关注 \(f(root)\)

考虑转移其实很复杂,设 \(V\)\(u\) 儿子的集合

\[f(u)=\sum_{k}\sum_{|S|=k}k\times \prod_{a\in S}f(a)\prod_{a\in (V-S)}g(a) \]

等等,如果我们把 \(k\) 这个因子砍掉,我们将会发现最后的答案就是 \(\prod_{v\in V}(f(v)+g(v))\)。当我们加上了 \(k\) 这个因子之后,这个式子变得棘手了。

考虑 \(\times k\) 可以视作这样一个变形:

\[\sum_{k}\sum_{|S|=k}\sum_{a\in S}\prod_{a\in S}f(a)\prod_{a\in (V-S)}g(a)\\ =\sum_{k}\sum_{|S|=k}\sum_{a\in S}f(a)\prod_{b\in S\land a\neq b}f(b)\prod_{b\in (V-S)}g(b)\\ =\sum_{a\in V}f(a)\sum_{a\notin S'}\prod_{b\in S'}f(b)\prod_{b\in (V-S'-a)}g(b) \]

而后面的部分其实就是 \(\prod_{v\in V}(f(v)+g(v))\) 除以 \((f(a)+g(a))\),我们完全可以一次 dfs 把这个东西 \(c_a\) 求出来,它是永远不变的。然后就变成了:

\[f(u)=\sum_{a\in V}c_a\times f(a) \]

换言之 \(f(u)\) 是其儿子的 \(f\) 的一个确定的线性组合。从根开始往下推,你会发现 \(f(root)\) 是所有叶子的 \(f\) 的确定的线性组合,同时叶子的 \(f\) 只能是 \(0/1\)

那么标号区间反转叶子的值就变得非常简单了,一个线段树维护即可。

时间复杂度 \(O(N+Q\log N)\)

记录

12. 无线电信号塔

难度很大的题,花了两个晚上的时间。

我们首先思考一个很弱的问题:\(Q=1\)\(L=0,R=n-1\) 的时候,如何去做这个问题?

如果选了 \(i\),设 \(L_i\)\(i\) 左边第一个满足 \(H_j-D\ge H_i\) 的位置,同理设出 \(R_i\),我们将发现:如果我们选了 \(i\),那么 \([L_i,i)\) 以及 \((i,R_i]\) 中的点都不能再选了。

我们将发现这个约束还是充分的。所以把问题本身转成了相对可做的形式。这个约束其实很像区间覆盖,考虑把所有三元组 \((i,L_i,R_i)\) 按照 \(R\) 排序,容易发现按照 \(R\) 排序后贪心是最优秀的。

加上其它一些简单的 case,我们大概可以获得 40pts 左右的分数(事实上已经比现场平均分高了,乐)。

我们思考一下,如果 \(D\) 是固定值,改成区间询问(即 subtask 6)如何进一步去处理?

容易想到一个错误的方向,就是说如果 \(R_i\lt R_j\) 那么一定有 \(i\lt j\),如果这个成立你就可以很方便地维护,但是我们发现很容易构造出反例,很显然两个区间可能存在包含关系。

但是这个时候会发现一种特殊情况:相交且不包含,如果是这样,那么 \(i,j\) 的交集大小恰好为 \(1\)。观察到后容易证明。

那么区间关系只有三种:包含,相交且交集大小为 \(1\),不相交。不相交的话,那么就毫无关联了,如果 \(a\) 包含了 \(b\),那么选 \(b\) 肯定会更优秀。

至于交集大小为 \(1\) 的情况,你只要把 \([L_i,R_i]\) 改成 \([L_i,R_i)\) 这样一个左闭右开的区间,则原条件合法就等价于你选的区间没有重叠部分。

此时就可以上 DS 维护了:因为 \(n\) 个区间是不变化的,如果 \(a\) 包含了 \(b\) 你就删除 \(a\),这样剩下的区间 \([L_i,R_i)\) 不包含其它区间,且剩下的区间两两无交。排序后就变成了询问一段区间里,剩下区间的个数,容易用各种序列 DS 维护。

当然你可能处理区间询问的时候还要判断一下左右两边边界能否还能塞进一个点,这个是容易的。

现在你可以获得大约 60pts 的分数了!让我们考虑更进一步,如果总是全局询问,而 \(D\) 会变化,如何处理(即 subtask 5)?

难点在于,随着 \(D\) 的变化,区间 \(L,R\) 也会变化。我们如何去研究?按照 \(D\) 排序后,我们发现,如果 \(a\) 开始就包含了 \(b\),再 \(D\) 更大的情况下它也会一直包含 \(b\)(特别提醒要判两个区间重合的情况,此时谁包含谁是看谁的 \(H\) 大))。所以我们最初令 \(D=1\) 筛选一遍后剩下的区间是可能有意义的,而随着 \(D\) 的增大,一个有意义的区间只会变得无意义,无意义的区间永远不可能重新变得有意义。

所以如果询问的 \(D\) 是升序给出,你就可以研究相邻的有意义区间什么时候产生合并,然后用优先队列去维护删除,可能还需要维护链表。

但是交互的形式决定了这个问题是在线的,如何处理?我们把 \(O(n)\) 个时刻的答案都预处理出来即可。

现在结合 subtask 5+6,我们需要在线查询某一个时刻某个区间的有意义区间数量和,运用预处理的思想主席树即可。

视实现复杂度在 \((n+q) \log n\) 或者 \((n+q) \log n\log w\) 不等。

记录

13. Shattrath City

很不错的基础多项式计数习题,适合我这样的人食用。

正难则反,我们考虑对所有非法排列计数。一种想法是直接容斥:枚举以哪些位置开头,形成的 \(n\) 连续段是一个 \(n\) 排列。

但是这里你就要想清楚一个问题,这样只不过是修改容斥系数的正负性。什么意思?就是说你这个容斥的想法,其实直接求合法排列,也是可以用的,只不过差异在 \((-1)\) 的上标上,换言之这样做和直接正着做是没有任何区别的,所以我们将看到这是一个不可做的方向。

考虑直接枚举第一个 \(n\) 排列构成的 \(n\) 连续段的开头,那么其后面的方案数是容易确定的,但是你要保证前面不出现 \(n\) 连续段,所以我们考虑容斥。

对于 \(j+n-1\lt i\) 来说,直接去掉 \(f(j)\times n^{i-j-1}\) 的贡献即可;那么对于 \(i-n+1\le j\lt i\)\(j\) 来说呢?其实是 \(f(j)\times (i-j)!\)

所以其实是 \(f(i)=n^{i-1}\times n! - \sum_{j\lt i-n+1}f(j)\times n^{i-j-n}\times n! - \sum_{i-n+1\le j\lt i}f(j)(i-j)!\),我们会发现可以分治 ntt 优化到 \(O(m\log^2 m)\) 的级别。

事实上很多半在线卷积可以通过生成函数优化到 \(O(m\log m)\),比如本题。

其道理就是因为 \(f\) 是被卷出来的:所以考虑设 \(F(x)=\sum_{i=1}^{\infty}f_ix^i,G(x)=\sum_{i=1}^{\infty}n^{i-1}n! x^i,H(x)=\sum_{i=1}^{n-1}i!x^i\),容易有:

\[F(x)=G(x)-F(x)G(x)x^{n-1}+H(x) \Rightarrow F(x)=\frac{G(x)}{G(x)x^{n-1}+H(x)+1} \]

多项式求逆即可。

记录

14. Gilneas

可能做过 NOI2021 轻重边会被误导方向,但首先我们有一个思路就是这个题肯定是离线下来搞的。

根据期望线性性我们只要把每条边的边权期望加起来即可。

一个操作想对一条边 \((u,v)\) 造成贡献,首先要覆盖到这条边的两个端点,其次要生效,同时,所有在他后面发生的,至少 覆盖 \(u,v\) 一个点的操作,都不能生效。

\(u\)\(fa_v\),那么观察到能对一对 \((u,v)\) 造成贡献的操作,\(x\) 应该位于 \(u\) 的子树内(且不包含 \(u\))。

考虑线段树合并去维护这个过程,每个节点只要存 \((1-p)\) 的积以及 \(\sum p_i\times after_i\),其中 \(after_i\) 是这个区间内位于它之后的操作的 \((1-p\) 的积。

显然 \(after\) 的计算里要考虑 \(x=u\) 的操作,所以线段树合并完还要加入 \(u\) 点的操作的全部信息;然后我们把答案加上根节点处的值即可;但是注意到这样,则 \(x=u\) 的操作可能被作为贡献算进去,此时减去它们的贡献是容易的。

复杂度 \(O((n+m)\log n)\)

这次不卡常了,但是 \(n=2\times 10^5\) 可以 dfs 爆栈,这就是 HDU!

记录

15. If You Can't Beat Them, Join Them!

之前刚做过 ABC261H 啊,就碰到了这个题,可谓是喜闻乐见了。

首先最后图的结果只有三种:胜,死循环,负;

死循环的图你随便选择无所谓。必胜的图至少选一个。必败的图可以选一些,但是存在限制的。

你发现如果一个图先手必胜,先手希望尽可能快的胜利;如果先手必败,它希望多拖延一会儿时间:这样你就可以选择一些必败的图了。

所以首先 dp 求出每张图的每个节点出发会是什么状态,对于胜/负的图还要再 dp 一次最后的步数,以先手必胜的图为例:首先你要保证胜负结果不变,所以有些点就不能走了,在这个新图上,就变成了先手希望最小化步数,后手希望最大化步数,和 ABC261 H没有本质区别了。

dp 的过程就是倒着类似拓扑+dijkstra的方式。时间复杂度 \(O(\sum (n+m)\log m)\)

记录

16. Pass to Next

模拟赛竟然场切 ARC E 了,泪目。

首先考虑我们是对可能合法的结果序列的乘积求和,所以应该从结果出发,考虑合法的结果序列是否存在性质;因为显然,不同的传递方式也有可能得到同样的结果。

我们会发现一个重要的事情:设 \(S_i\)\(i\rightarrow (i+1)\) 的数目,则我们可以同时把 \(S_i\) 减去一个相同的值,结果不会变化。

换言之,\(S_i\) 至少有一个 \(0\) 存在。

\(S_i=0\),那么可以把环从 \(i-(i+1)\) 处断成链。然后你会发现此时可能的结果序列和 \(S\) 序列形成一一对应。

这样就可以说明结果序列和至少存在一个 \(0\)\(S\) 序列形成一一对应。

不妨假设我们断的是 \(n-1\) 这条边,你将发现我们就是对所有可能的 \(\left\langle 0\le S_i\le a_i\right\rangle\),去求 \(\prod (a_i-S_i+S_{i-1})\) 的和。

这个乘积的展开式可以由每个 \(1\le i\le n\) 的部分提供一个因子得到:\(a_i / -S_i / S_{i-1}\)

定义 \(\sigma_k(n)=\sum_{i=0}^{n}i^k\),在这里令 \(0^0=1\)

注意到如果没有 \(S_{i-1}\) 那么每个部分是独立的,只需要把 \(a_i\times \sigma_0(a_i)-\sigma_1(a_i)\) 全部乘起来即可。

问题在于会混入 \(S_{i-1}\) 这一项。

考虑 dp:设 \(f(i,0)\) 表示前 \(i\) 个因子的贡献确定,且 \(i+1\) 这一项不取 \(S_{i}\) 作为因子的乘积之和;类似地,\(f(i,1)\) 表示前 \(i\) 个因子的贡献确定,且 \(i+1\) 这一项取 \(S_{i}\) 作为因子的乘积之和,我们将看到:

\[f(i,0)\times (a_i\times \sigma_{0}(a_i) - \sigma_{1}(a_i)) \rightarrow f(i+1,0) \\ f(i,0)\times (a_i\times \sigma_{1}(a_i) - \sigma_{2}(a_i)) \rightarrow f(i+1,1) \\ f(i,1)\times \sigma_0(a_i) \rightarrow f(i+1,0) \\ f(i,1)\times \sigma_1{a_i} \rightarrow f(i+1,1) \]

此时我们可以单次 \(O(n)\) 转移了。但是我们要 \(O(n)\) 枚举断环成链的位置,所以这个做法是 \(n^2\) 的。另外需要注意到,当我们把环从 \(i-(i+1)\) 断开的时候,实质上必须钦定 \(S_{1\sim (i-1)}\) 全部不为 \(0\),所以在这部分你的转移需要微调。

我们发现上述转移其实是矩阵的形式:对于每个位置处理出 \(2\times 2\) 矩阵;然后不管怎么断环,矩阵都是不变的,预处理矩阵前后缀积即可单次 \(O(1)\) 求得答案。

时间复杂度 \(O(n)\)

记录

17. Even XOR

很牛逼的题,这里给出我的思考方向。

考虑一个事情,就是如果我们去掉“要么 \(|T|\) 是奇数”这个条件,改成:任意两个不同子集的 xor 和不能相同,那么这其实类似一个线性基的结论在,就是 \(|S|\) 的大小不超过 \(N\)

现在回到这个题,我们容易猜想:\(|S|\) 的大小是否存在一定限制?

考虑这个题的实质是:任意两个奇偶性相同的子集,xor 和不能相同。所以我们会发现 \(|S|=N+1\) 就是最大值了(此时奇偶子集各有 \(2^N\) 个)。

所以本题中 \(|S|\) 的大小确实有限制:\(|S|\le N+1\),这样首先这个问题就可做了很多。

考虑有一个合法的集合 \(S\),我们要加入一个新元素 \(x\),那么什么时候可以加入?当且仅当 \(S\) 中不存在一个奇数子集,xor 和为 \(x\)

\(S\) 是合法的,所以 \(S\) 中任意两个奇数子集 xor 和都两两不同。所以你有 \(2^{|S|-1}\) 个奇数子集,也就意味着有 \(2^{|S|-1}\) 个数不能加入。

因此,设 \(dp(i)\) 表示 \(|S|=i\)\(S\) 个数,有转移:\(dp(i+1)=dp(i)\times (2^N-2^{i-1})\)

然而我们是对集合计数,考虑如果有一个合法的集合 \(\{1,2\}\),那么你先加入 \(1\) 再加入 \(2\);先加入 \(2\) 再加入 \(1\) 都会算一次,所以我们要把 \(dp(i)\) 最后除以 \(i!\),也就是说答案是:

\[ans=\sum_{i=0}^{N+1}\frac{dp(i)}{i!} \]

时间复杂度 \(O(N)\)

记录

18. >=<

题目名可爱捏。

因为要最小化 \(A\) 的和所以我们考虑全填 \(1\)

如果没有 \(x=1\) 或者 \(y=1\) 的约束那么就肯定合法了,如果约束是 \(x=y=1\) 那也无所谓。

如果是 \(x=1,y\gt 1\) 这样的约束呢?我们钦定 \(A_p=1\) 不动,让 \(A_q=y\),这样可以取到一个暂时的最小值。

当然这样肯定会违反一些别的约束,你发现此时所谓违反无非就是原本两个同小,但是此时一个变得大于其约束了,那么另外一个也必须大于对应的约束。

通过上面的分析,直接不断进行调整其实是可以的。但是有一个转化方法可以大大简化我们的思路:考虑实质上就是给出了两个约束:\(a_p\le x-1 \Leftrightarrow a_q\le y-1\) 以及 \(a_p\le x\Leftrightarrow a_q\le y\),这个转化可以从 2-SAT 推得,另一种思想是,小于,等于,大于三种情况过于复杂,我们简化成小于等于和大于两种情况。

所以其实可以看成给了 \(2\times K\) 个约束。对于约束 \(x,y,p,q\) 来说,如果有 \(a_p\gt x\),也就意味着 \(a_q\gt y\) 了。不断地这样进行调整即可,如果最后调整出来有 \(\gt M\) 的那就直接无解喽,否则最终的 \(A\) 就是答案,所以其实可以出成构造的......

时间复杂度 \(O((n+k)\log n)\)

记录

19. Yosupo's Algorithm

很有启发性的好题!

乍一眼这个题,维度限制非常的多,首先红蓝点之间的 \(y\) 有约束,红蓝点的 \(x\) 还被约束,而且还要问红蓝前权值和的最大值。

那么我们要有两个意识:第一,多维度的约束,往往无法在线解决;第二,我们往往会尝试去掉一些维度,思考弱化的问题,这个维度的限制越简洁越好,这样我们可以通过一些 DS 手段,最后加入这个维度的影响。

值得一提的是,碰到这种看上去很繁杂的题,不管怎么说,至少需要花费一定时间思考是否存在根号算法,尽管本题并不是根号题。

去掉 \(y\) 这一维度的限制,首先它形式足够简单,而且我们发现这个维度的限制和询问本身是无关的。

此时再去考虑离线这个问题,就容易想到二维数点:对于红点 \(i\) 和蓝点 \(j\),把 \((x_i,x_j)\) 看作一个权值为 \(w_i+w_j\) 的点,然后变成了简单的二维数点问题。

然后你会发现一个事情,就是我们总是能取到权值最大的那个红点,或者权值最大的蓝点,作为一组最优答案。

现在加入 \(y\) 这一维度的考虑:把所有红蓝点放在一起按照 \(y\) 排序,用类似 cdq 分治的思想去掉 \(y\) 的限制,这样你会找到 \(T(n)=2T(\frac{n}{2})+O(n)\) 个点对,也就是说最后一共只有 \(O(n\log n)\) 个有意义的点,直接二维数点即可。

时间复杂度 \(O(n\log^2 n+q\log n)\)

记录

20. Simple Speed

常规地应该想到从小到大加入数字的方法,这是一个比较套路的东西。

如果你没有这个想法,或者不是很熟练,那么我们考虑把最后序列 \(B\) 的每个位置放到二维平面上:即每个点对应 \((i,B_i)\),连接相邻的点。

现在我们用一条 \(x=k\) 的线从下往上扫描这条折线,我们来研究任意时刻,我们这条线所截的下半部分长什么样子。

不难发现这个部分由若干个合法序列组成:且假设有 \(j\) 个序列,那么第 \(1\sim j-1\) 个序列的结尾都应该是 \(k\)(截线高度,说人话是你当且加入的数的最大值);第 \(2\sim j\) 个序列的开头都应该是 \(k\),至于最外层两个端点倒没有限制。

显然我们加入值为 \(k+1\) 的若干元素时,首先必须把 \(j-1\) 个空位填满,然后剩下的再在 \(j+1\) 个空位里随便放。

\(dp(i,j,k)\) 表示加入了 \(1\sim i\),有 \(k\) 个序列,且最外层两个端点有 \(j\) 个是 \(i\) 的方案数。

此时我们可以在 \(O(n\times A)\) 的时间内计算 dp。

最厉害的地方来了,如果你把这个暴力的转移写出来了,你会发现,如果 \(i,j\) 固定,那么满足 \(dp(i,j,k)\neq 0\)\(k\)\(O(1)\) 级别的。

所以此时这个 dp 可以很容易地优化到 \(O(n)\)

记录

21. Xor Sum

是非常非常非常非常非常牛逼的题。

第一步要想到二分,不必多说了。

这个问题棘手的在于什么?在于,\(X\) 限制了你每一位,为 \(1\) 的数的个数的奇偶性,这是每位独立的;但是 \(S\) 又限制了和;还有元素都不查过这样,从多个角度给出了一些限制,令人无从下手。

发现一个事情:设 \(b_i\) 代表多少个数第 \(i\) 位为 \(1\),我们发现事实上满足 \(X\)\(S\) 限制的 \(b\) 数组不止一种,我们可以通过调整的手段实现两个 \(b\) 的转化。

但是我们始终要保证 \(\max A_i \le lim\) 啊,你会发现这个限制和 \(b\) 结合起来会有非常良好的效果!

具体地,我们考虑从高往低贪心,那么有些数是确定已经 \(\lt lim\) 的,记为集合 \(D\);那么我们每一位要让恰好 \(b_i\) 个数为 \(1\),你发现我们肯定会嗯往 \(D\) 集合里塞满,这样会产生尽可能多的新的在 \(D\) 集合里的数,运用这个策略无解的情况也是容易的:就是 \(lim\) 上这一位是 \(0\),但是你往 \(D\) 集合塞满了 \(1\) 以后还没塞完。

现在,考虑把这个良好的贪心和 \(b\) 的调整结合在一起:既然我们是从高位往低位贪的,就想让 \(b\) 的调整也是从高位往低位调:所以我们要让初始的 \(b\) 尽可能往高位靠拢,然后不断的往低位传递,具体的,是 \(b_i-=2\),且 \(b_{i-1}+=4\)(你要保证 xor 的限制不变)。

所以最初的 \(b\) 的构造是这样的,设 \(D\)\(S-X\),首先我们将看到 \(D\) 是非负偶数的时候才可能有解,然后令 \(b_i\)\(X\)\(i\) 位的值 \(+2\times\) (\(\frac{D}{2}\)\(i\) 位的值),那么我们就可以把贪心过程和 dp 结合起来了:设 \(dp(i,j)\) 是考虑最高的 \(i\) 位,且 \(|D|=j\),向后传递的最少数量(你会发现这个数量一定是 \(4\) 的倍数)。

这个 dp 单次是 \(O(n\log S)\) 的没有问题,但是本题 \(n\) 高达 \(10^{18}\) 级别,难道我们的路就走死了?

神来之笔来了:我们可以证明,\(j\le 3+\log S\),且如果 \(f(i,j)\) 可以转移到 \(f(i-1,k)\),一定满足:\(j\le k\le \max\{4,j+1\}\)

或许现在我们仍然一头雾水。首先我们看到一个事实,根据我们构造 \(b_i\) 的方式,那么有 \(0\le b_i\le 3\)

所以,如果存在某个 \(j\ge 3\) 满足 \(f(i,j)=0\),那么一定有解:因为你每一位不超过 \(3\)\(1\) 肯定能塞进集合 \(D\) 中。

理清了这两点后,让我们回到这里 dp 的转移。

如果我们能从 \(j\) 转移到 \(k\),我们会发现转移到 \(k+2\) 一定是不优秀的(这就说明了 \(j\) 只能转移到 \(j\) 或者 \(j+1\),至于那个 \(4\) 就有另外的讲究)。

何以见得?你要意识到我们转移到 \(k+2\) 是牺牲了两个 \(1\) 扔到后面去的,但是到后一位这个 \(2\) 就变成了 \(4\),而如果你选择这次转移到 \(k\),下一次 \(lim=1\) 的时候你把那两个补回来,效果和你提前转到 \(k+2\) 一样,但是传递的会更少。

有没有特例?有的,当后面不再有 \(lim_i=1\) 的位的时候,这个时候,你就不能再往后有贡献附带了,我们会发现,如果 \(f(i,k+2)\) 可以为 \(0\),那么你 \(f(i,k)\) 在这一位用掉了更多的 \(1\),当然往后也是 \(0\) 对吧,所以看上去 \(k\) 是全面碾压 \(k+2\) 的,但并非如此。因为你既要 \(f(i,j)=0\) 又要 \(j\ge 3\),所以 \(k\) 全面碾压 \(k+2\) 只在 \(k\ge 3\) 的时候成立,这也就是那个 \(\max\{4,j+1\}\) 中那个奇怪的 \(4\) 的由来!

你会发现通过这个优化实质上单次复杂度仅有 \(O(\log^2 S)\),算上二分,这个题的总复杂度是 \(O(T\log^3 S)\) 的!

值得反复品味的好题。

记录

22. Simple Math 4

和上面的题形式很像,事实上确实存在相似点,也存在不同点。

本题中约束最烦人的不再是元素之和了,而是取值范围有上下界,而且你注意到这里的答案 \(S\) 不存在可二分性。

我们沿用上面的贪心,你发现这次我们要维护两个东西:就是前缀 \(=R\) 以及前缀 \(=L\) 的个数(特判 \(L=R\))。

那么这样直接 dp 状态都是 \(O(n^2 \log X)\) 的。

关键结论:至多有 \(O(\log X)\) 个数不为 \(R\),否则必有两个这样的数 lowbit 相同,同时 +1 不改变 xor 和。

所以现在状态就只有 \(O(\log^3 X)\) 级别了,考虑转移:看上去直接做是单次 \(O(\log X)\) 的,但是你发现关于 \(L\) 的限制,如果限制为 \(1\),那么强制只能都填 \(1\);否则你最多会留一个依然和 \(L\) 相等的,所以转移单次是 \(O(\log X)\) 的,总时间复杂度 \(O(T\log^4 X)\)

记录

23. 单枪匹马

感觉没什么好多说的...... 首先手玩一下发现 \(f(a,b,c,d)\) 长的就很恐怖感觉没啥性质,然后发现题目让你把分子分母分别输出,肯定有猫腻。

发现把 \(\frac{x}{y}\) 写进向量以后每次往前面加个数就是乘了个矩阵。这题是在线区间询问,有两种方法:线段树,或者手动给 \(2\times 2\) 矩阵求逆。

采用后一种方法的话时间复杂度是 \(O(n+q)\) 的。

记录

24. Out of Sorts

奶牛思维题一向克制我,今天罚坐一小时干出来了,可喜可贺。

看到冒泡排序就要意识到这是个带有推性质部分的题目。首先这类问题有一个解决利器是建立逆序和原数组的一一对应,但你会发现本题中“分隔”这个概念体现在逆序上并没有任何性质,所以本题里考虑逆序方向是一个死路。不过值得一提的是,你会发现如果我们想让题面里给的那个暴力 TLE,那么构造足够强大的数据方法就是生成一个 \(\max\) 分布均匀且较大的逆序(比如 \(10\)\(5000\) 这样的),然后转成对应的原数组。

回到正题。考虑把贡献拆开来研究,即研究单个对象的贡献。冒泡排序容易让我们联想到逆序对,考虑一个逆序 \(a_x\gt a_y\),会对 \(cnt\) 造成的影响,这将是我们考虑的方向。

你还要注意到一点:事实上每层递归里,那个 do while 只会执行恰好一次,而且你发现除了初始的递归以外,那个恰好一次的 do 一定是有意义的。所以我们第一次冒泡过程暴力模拟,然后分出若干个段,对这些独立的段分别来考虑。

不妨对应每个位置来研究,毕竟说白了,一个数的贡献是它被冒泡排序的次数。分类来看:它作为 \(a_x\gt a_y\) 中的 \(y\) 的时候,贡献就是前面比他大的数的个数;当作为 \(a_x\gt a_y\) 中的 \(x\) 出现的时候,贡献实质上是它执行冒泡的次数:即你要找到一个最靠后的 \(y\) 满足 \(a_y\lt a_x\),然后区间 \((x,y]\) 里大于等于 \(a_x\) 的数的个数 \(+1\) 就应该是这个位置作为这个位置的贡献。

不难发现可以通过单调栈 + bit 的手段做到 \(O(n\log n)\)

记录

25. 捉迷藏

动态修改点集,维护点集直径,看上去就很毒瘤。

然而你只需要知道一个结论,设 \(f(X)\) 是集合 \(S\) 的直径点集(显然大小不超过 \(2\)),则对于任何的两个点集 \(S,T\),都有 \(f(S\cup T)\subset f(S)\cup f(T)\)

然后利用欧拉序,\(O(n \log n)\) 预处理,\(O(1)\) 维护两点距离,线段树直接对标号区间维护即可。

记录

26. Security by Ambiguity

模拟把这个题加强了一下:\(n\le 2\times 10^5\),且答案模一个不一定为素数的数 \(P\)

首先难点是这个原文到密文的变换,并不是一个非常简单的形式,让人看的云里雾里的。

如果 \(P_i=j\),那么对应的就有 \(Q_j=i\),所以令 \(X''_i=Q_{X'_i}\),反过来就是 \(P_{X''_i}=X'_{i}\)

\(X'_{i}\) 显然是 \(X_{P_i}\),所以有 \(P_{X''_i}=X_{P_i}\),你知道 \(X''\) 就是给出的序列 \(A\),所以实际上是:

\[X_{P_i}=P_{A_i} \]

现在 \(A\) 确定了,我们想知道多少个 \(X\),存在一个 \(P\) 使得满足上面的条件。

你会发现 \((P_i,P_{A_i})\) 其实是一个 “下标-值” 的对应关系:指定下标为 \(P_i\) 的位置,它的值是 \(P_{A_i}\)。所以,存在一个 \(P\rightarrow X\) 的映射关系:如果 \(P\) 确定,有唯一的对应的 \(X\) 被确定。

但是这个集合并不是双射:因为答案显然不永远是 \(n!\)\(n!\)\(P\) 的总数),这意味着不同的 \(P\) 可能得到相同的 \(X\)

自然地就有一个想法产生:什么样的 \(P\) 会导出相同的 \(X\)?我们刚才说了 \(P\) 建立起了 “下标-值” 的映射关系:所以考虑有序二元组 \((P_i,P_{A_i})\) 所构成的集合,如果两个 \(P_1,P_2\) 所构成的集合相同,也就等价于它们生成相同的 \(X\)

考虑连接所有 \(i\rightarrow A_i\) 的边,形成的内向树森林,你会发现 \(P\) 实际上是将节点重新编号了。我们认为两个基环树森林相同当且仅当边集相同,然后询问最后有多少种可能的基环树森林,到这里问题就变成我们较为熟悉的形式了!

不妨来思考如果仅是一棵树,那么怎么做?首先总答案是 \(n!\),你会发现如果一个节点 \(u\)\(k\) 颗同构子树那么答案就除以 \(k!\)

如果是树的森林,那么我们最后还要考虑同构树的个数。

现在回到基环树,对于每个环上挂的子树,我们的过程不变,最后对所有基环树进行同构判断也是依旧有的,那么环上也是要处理的:考虑把基环转环,每个节点上挂的子树和原来挂的子树依旧重构,这种情况下我们把每个环上点的哈希值处理出来,此时问题变成了一个字符串的最小循环节问题。至于基环树的哈希,只要求出这个环的最小表示法即可,这是环哈希的常用套路。

不难发现此时复杂度是 \(O(n\log n)\) 的,因为你需要开 map 存哈希值。除数不是模数的情况,你发现任意时刻答案都一定是整数,所以可以暴力分解质因数,维护每个质因数的出现次数,你发现这个 \(\log\) 和 map 的那个是独立的,所以时间复杂度依然是 \(O(n\log n)\)

记录

27. Weighted Beautiful Tree

还是比较简单的题。

\(dp(u,i)\) 表示让 \(u\) 子树内的边合法,且最后点 \(u\) 的权为 \(i\) 的最小代价。

你会发现 \(i\) 只有 \(O(deg_u)\) 级别个取值。

所以有意义的状态数是 \(O(n)\) 的,转移的时候将有意义的值排序,然后双指针即可。

需要特判 \(u\) 的点权和 \(u-v\) 的边权 \(w\) 相等的情况。

时间复杂度 \(O(n\log n)\),实现好应该可以 \(O(n)\)

记录

28. 众数

大概是今年 NOI 最简单的一道题,正解很快看了出来但是挂在了实现上... 深感自己和 NOI 选手的差距很大。

特殊性质 A:\(n=1\) 且没有操作 \(4\),则问题实质上是区间众数。

特殊性质 B:任意时刻序列只有数字 \(1\)\(2\),则你只需要记录 \(1\) 的个数即可。

特殊性质 C:没有删除操作,这个我们一时没有什么好的想法。

不难发现性质 A 和 B 和正解完全没有关系,纯属让你多拿一点分。

你只要意识到一点,把序列 \(A,B\) 拼起来得到的绝对众数,它要么是 \(A\) 的绝对众数,要么是 \(B\) 的绝对众数。

所以如果查询 \(n\) 个序列拼起来的绝对众数,可以分治得到两边的绝对众数,然后再检查它们是不是整个区间的绝对众数。

你会发现这里需要涉及到一个“查询一个数 \(x\) 在某个序列的出现次数”这样一个问题,我们试图让其低于 \(O(\log n)\),一个想法是利用哈希表做到近似 \(O(1)\) 的复杂度。

这样时间复杂度大约在 \(T(n)=2T(\frac{n}{2})+O(n)\) 左右,所以对于询问,你得到了一个 \(O(C_m \log C_m)\) 的回答询问的做法。

现在问题变成了在线地维护每个序列的众数。

合并两个序列,自然想到启发式合并,这里就占了 \(O(C_l \log C_l)\) 的复杂度;这个时候我们就明白特殊性质 C 的用处了:我们可以 \(O(1)\) 地处理众数的变化,但是如果带上删除呢?我的想法是用 set 去动态维护,但是这样就会让常数变得很大,而且这个 set 的使用还会出现在合并的过程,所以复杂度又变成 \(O(n\log^2 n)\) 了。

在洛谷,这样的实现只能获得 \(85\sim 95\) 的分数。我听说 NOI 现场今年评测机极其快,所以存在 AC 的概率。

那么怎么优化呢?你发现其实可以用动态开点线段树直接动态维护序列的众数,而且合并两个序列的时候直接线段树合并即可,这样时间复杂度即为 \(O(n\log n)\)

启发:我们有时候想替换掉我们的 set 的时候,往往可以采用线段树去解决。

记录

29. 挑战 NPC II

昨天我说错了,这个才是 NOI 最简单的题,想了一会儿就 1A 了...

题面已经告诉我们是树哈希相关了,其实也不难想到:因为 \(k=0\) 的情况,判断树同构也要用到树哈希。

考虑从根往下匹配,这里有个结论,如果两个子树已经匹配了,那么不会把它们拆开:假设两个树中有一对同构子树形如 \(U\),如果你让第一颗树里的另一颗子树 \(V\) 去和 \(U\) 匹配,那么第一颗子树里的 \(U\) 去和 \(X\) 匹配,你发现我们可以直接换成 \(V-X\) 匹配,\(U-U\) 匹配,要删除的点数不变。

考虑 \(k=1\),我们会发现按照上面的贪心匹配最后最多只会剩下一对子树没有匹配,不断重复这个过程就是 \(O(n)\) 的。

现在回到 \(k=5\) 的情况,最后肯定不超过 \(k\) 对子树未匹配,\(k!\) 暴力枚举匹配关系即可。

道理何在呢?首先这里你不管怎么配对,都至少要删除一个点;如果剩下的子树很多,把 \(5\) 平均分掉,那么就变成了 \(k=1/2/3\) 规模的小问题;如果剩下 \(1/2\) 对子树,那么在这一层贡献的计算量就是 \(1\) 或者 \(2\),而且你注意到如果剩下两颗子树,至少会从 \(5\) 的规模变成 \(4\) 的规模,所以计算量 \(\times 2\) 也不会发生太多次。事实上通过一定分析,可以认为暴力匹配的复杂度就是 \(O(nk!)\) 的。

记录

30. Candies for Children

今天模拟竟然独立做出 2600* 的数学题了。

首先,我们对这个题做出一定的转化:这个过程可以等价于转了若干圈回到 \(l\),然后走到 \(r\) 结束。设转了 \(M\) 圈,有 \(a\) 个贪心的孩子,则第一部分会消耗 \(M\times (n+a)\) 个糖果。

有一个细节你需要注意到:贪心的孩子,取的是 \(\min\{2,K\}\) 颗糖果,通过一些手段,我们可以把它变成“贪心的孩子,取 \(2\) 颗糖果”:你只需要对于 \(K\)\(K+1\) 的情况都去算一遍答案,然后保证如果 \(l\rightarrow r\) 这一段有若干个贪心的孩子,都会尽可能贴着 \(r\) 那一端,同时,当你算 \(K+1\) 的情况的时候,\(r\) 必须是一个贪心的孩子。不难发现这样就把问题简化了一些。

如果我们暴力枚举 \(a\),则转一圈就要 \(n+a\) 的代价,用 \(K\) 除以 \(n+a\) 所得的余数就可以得到唯一确定的 \(b\)\(b\)\(l\rightarrow r\) 的贪心孩子的个数)。

\(n\) 很大的时候这个做法就行不通了,此时我们枚举 \(M\),然后你会发现会去解这样一个方程:\((M+1)b+Mc=x\),其中 \(x\) 是个能确定出来的常数,\(c=a-b\),同时 \(b,c\) 具有一定上下界,你需要最大化 \(b+c\) 的值,直接 exgcd 后调整即可得到答案。

\(n=\sqrt{K}\) 去分治则容易做到 \(O(\sqrt{K}\log K)\) 的复杂度,而且事实证明这个做法极其快。

记录

31. Snuke Panic (2D)

最近的场中比较简单的 H 题。

容易想到按照 \(y\) 为第一关键字,\(t\) 为第二关键字排序,这样,如果能先吃掉 \(i\) 再吃掉 \(j\),说明 \(i\lt j\)

然后就可以考虑设 \(dp(i)\) 代表吃了若干个,最后吃的是第 \(i\) 个能得到的最大收益,方便起见我们加入一个 \(x=y=t=A=0\) 的点,容易发现它一定排在第一个。

则有转移 \(dp(i)=\max_{j\lt i}\{dp(j)+A_i \mid dis(i,j)\le \Delta t\}\)

通过讨论 \(x_i\)\(x_j\) 的关系,可以拆开绝对值,发现是两次三维数点,利用 cdq 分治做到 \(O(n\log^2 n)\),这里可以用维护前缀 max 的 BIT 来替代线段树。

记录

32. Max Limited Sequence

一道非常适合出现在 OI 的高质量计数。

首先会有这样一个想法:可以容易的处理出每个位置处理出来的最大值 \(lim_i\),然后对于一个约束 \([L,R,a]\),只有 \(lim_i=a\) 的那些数才可能满足这个条件;所以我们可以每次把 \(lim\) 相同的拿出来处理,把每次的情况乘起来就是答案。

当值相同的时候,一个位置就只有两种情况:顶到上界 \((1)\) 或者不顶到上界 \((M)\)。我们把所有 \(=lim\) 的位置拉出来重新编号,设 \(dp(i)\) 是最后一个顶到上界的位置是 \(i\),让右端点 \(\le i\) 的询问全部合法的方案数,那么所有能转移到 \(dp(i)\)\(dp(j)\) 构成一个区间且有单调性质,贡献为 \(M^{i-j-1}=M^{i-1}\times M^{-j}\),通过双指针+前缀和的手段可以 \(O(k\log k)\) 处理,其中 \(k\) 是单次的询问和位置数之和。

所以总复杂度是 \(O((n+q)\log n)\) 的,实现好的话写起来非常舒服。

记录

posted on 2022-08-03 11:20  Cry_For_theMoon  阅读(252)  评论(2)    收藏  举报