Solution Set before NOI2024
前情提要:省选太唐没进队,现在是菜 D。
「ARC175E」Three View Drawing
原神。考虑令 \(m\) 为 \(\sqrt k\) 向上取整。那么有 \(m^2-2m+1<k\le m^2\)。考虑一种能够覆盖某个视图一个角的做法,那么直接覆盖两个角,中间留一条缝,或是宽度为 \(2\) 的缝(这种情况下有可能有奇偶性的问题,但是因为宽度为 \(2\),一定可以再覆盖对角线上的一个点来修正)就可以了。
「AT_dwacon6th_prelims_E」Span Covering
学习 DP 的最好方法永远是做 AtCoder 的题。
首先将线段从大到小排序。
定义 \(f_{i,j,k}\) 表示用了前 \(i\) 条线段,构成了 \(j\) 个连通块,连通块大小之和为 \(k\) 的方案数。注意这里我们不关心连通块之间的距离关系,只关心连通块的相对位置以及每个连通块内的安排方式。这样就可以枚举加入一条新线段之后的情形了。时间复杂度可以做到 \(O(N^2X)\)。
「BZOJ3812」主旋律
差不多联赛之前的时候拉过这道题,没做,省选狠狠破防。
考虑求有向图 DAG 子图的数量,就是直接枚举一层没有出边的点。但是容易发现会算重,容斥系数是 \(-1^{|S|}\),其中 \(S\) 是枚举的这个点集。
那么这个题改成枚举强连通分量集合,然后容斥系数就是 \(-1^{k}\),其中 \(k\) 代表构成的强连通分量数量。时间复杂度 \(O(3^n+m2^n)\)。
「HNOI2015」落忆枫音
唐。考虑只是一个 DAG,答案就是除 \(1\) 以外的点的入度之积。然后考虑加一条边,仍然用这个方法算答案,多的一定是一个基环树。拓扑排序后从 \(t\) 到 \(s\) 进行 dp 就可以消除这一部分的贡献。复杂度可以做到线性。
「CF1149D」Abandoning Roads
先只考虑 \(a\) 边,假设它们构成了若干个连通块。那么我们要做的就是从 \(1\) 走到 \(x\),并且走的 \(b\) 边不能连接两个相同连通块,并且离开某个连通块后就不能再回来。容易想到 \(\mathcal O(2^n\text{poly}(n))\) 的做法。考虑一个非常巧妙的优化,当一个连通块的元素个数小于 \(4\) 时,其不可能被经过多次,可以不管。所以状压记录的连通块数最多只有 \(18\) 个,就可过了。
「CF1693E」Outermost Maximums
抽象题号。考虑从大到小扫,然后让每个数变成前后缀最大值的较大者,就有 \(\mathcal O(n^2)\) 了。整正解的做法是打标记,当一个数的前缀或后缀第一次被扫到时选另外一个,就可以方便直接在树状数组上查询了。复杂度就能做到 \(\mathcal O(n\log n)\) 了。
「AGC016F」Games on DAG
又是一道 AT 的 dp 好题啊。原题意可转化为求 \(\text{SG}(1)=\text{SG}(2)\) 的方案数。怎么刻画 \(\text{SG}\) 的值呢?定义 \(f_S\) 为只考虑 \(S\) 的连通子图,使得满足相等条件。转移仍可以套路地枚举 \(\text{SG}\) 为 \(0\) 的部分,然后考虑一下中间边集的选法。这样复杂度是 \(\mathcal O(3^nn)\) 的。
「HAOI2015」数组游戏
感觉博弈论出题人有点魔怔了。我们可以通过激烈的转化把异或 \(1\) 改为加 \(1\) 的操作。然而思考 \(\text{SG}\) 函数的计算方式,可以发现只有 \(\mathcal O(\sqrt n)\) 种不同的取值。但是每种暴力算的话复杂度还是不可接受的。发现里面再整除分块一次就可以了,复杂度是 \(\mathcal O(n^\frac{3}{4})\),具体证明随便积分一下就可以了。
「SP11414」COT3-Combat on a tree
考虑写出 \(\text{SG}\) 函数的递推式,看着似乎很答辩,但是可以直接可合并 01trie 就可以维护,异或就打标记,查询 \(\text{mex}\) 就二分即可。复杂度是 \(O(n\log n)\) 的。
「AGC010F」Tree Game
牛题。考虑先钦定根,然后考虑一个子树是先手必胜还是必败状态。从某个点不能移动到先手必胜的某个子树,只能移动到先手必败的子树,而后手肯定会移回根。故只用判断一个点的先手必败的儿子的权值的最小值,与该点权值进行比较就可以了。
「AGC022E」Median Replace
考虑贪心,首先连续的 \(0\) 直接缩,然后再把相邻的 \(01\) 去掉,看最后是什么。那么就可以从左往右,遇到 \(000\) 和 \(01\) 就删(但是 \(10\) 不行,因为后面可能接 \(00\) 之类的)。那么只有有限个状态,就可以 dp 了。
「HNOI2010」城市建设
感觉 OI 学到一定程度确实是神学了。考虑 cdq 分治。我们对于一个区间内操作涉及到的边设为 inf 跑一边,没有用到的边一定不可能在之后用掉,删除。再把它们设为 -inf 跑一遍,用到的边以后一定会用到,就缩点。复杂度是 \(\mathcal O(n\log^2 n)\) 的。细节有点答辩,思路非常劝退啊。当然也是可以直接用 LCT 的,只不过会更答辩。
「CF1746F」Kazaee
我们考虑随机映射,那么显然如果区间和不是 \(k\) 是的倍数显然不合法,但是是 \(k\) 的倍数不一定合法。发现是 \(k\) 的倍数还不合法的概率大概是 \(\dfrac{1}{k}\),所以直接跑个二三十次就可以了。感觉是基础技术啊。
「AGC060C」Large Heap
我看的题解怎么都那么神奇.jpg。
定义 \(f_{i,j}\) 表示左边填了 \(i\) 个,右边填了 \(j-1\) 个并且要求 \(i\) 比 \(j-1\) 后填,比 \(j\) 先填的概率。转移的时候有一点不方便。但是其实可以灵活利用定义,将 \(f_{i,j}\) 转移到 \(f_{i+1,j}\) 上面和 \(f_{j,i+1}\) 上面即可。
「NOI2014」购票
首先,动态开点李超树空间是 \(\mathcal O(n)\) 的,因为进到空节点就没必要往下走了。其次,为了避免撤销,我们使用出栈序,即每个点结束搜索时的时间戳。这样空间就是严格 \(\mathcal O(n\log n)\) 了。
「NOI2021」量子通信
大水题。考虑 \(16\) 个绑一起,那么如果满足要求,必定有一块是完全一样的。枚举在哪个块一样,并且枚举在这个块跟它一样的所有串。由于数据随机,这样做的复杂度是有保障的。
「CQOI2017」小 Q 的草稿
有一种不太一样的单 log 做法。首先可以把与三角形相交看成与其中某一条边相交。那么我们考虑统计一条线段交的边的数量。这可以转化成两条射线的答案之差。所以我们现在要考虑的问题是对于一个原点,有若干个关键点和若干条线段,求原点到每个关键点的射线交的线段。极角排序后不难区间修改,最后再查询。
「CEOI2011」Balloons
把答案的式子写出来,显然我们可以维护一个最终的 \(r\) 单调下降的栈,只有栈里面的可能有用。但是还是不能把栈里的全部遍历。但是考虑一个事情,就是当目前得到的 \(r\) 比栈里某一个小的时候,就不用往下遍历了。并且前面遍历到的一定会被弹出。所以可以容易地做到线性。
「THUPC2019」摆家具
比较阴间的题。令 \(f_{S,i}\) 表示与 \(S\) 有 \(i\) 位不一样的权值和,\(g_{i,j}\) 表示对一个状态操作 \(i\) 次后与初始状态有 \(j\) 位不一样的方案数。那么有了这两个东西答案就不难算了。第一个东西可以直接 \(\mathcal O(n\log^2n)\) 的 dp 就算出来,第二个东西是个线性变换,直接预处理 \(M^k\) 和 \(M^{kB}\) 然后查询做两次矩阵乘法就可以了,其中 \(0\le k<B\)。
「CF986F」Oppa Funcan Style Remastered
一句话做完。考虑 \(k\) 的不同质因子数量。\(0\) 或 \(1\) 特判掉,\(2\) 就 exgcd,\(3\) 及以上选择最小那个跑同于最短路。此时你会发现选的那个不超过 \(10^5\),所以复杂度是对的。
「NOI2019」弹跳
感觉还是多学了一种 Dijkstra 的思路吧。对于修改一个区间的问题,其实可以通过用 set
维护剩余电击,用堆维护修改操作。每次从如果该操作的区间空了就去掉这个操作,否则从其区间中随便选一个来松弛,并把它从 set
里删掉。这样做时间是 \(\mathcal O((n+m)\log^2n)\) 的,空间时 \(\mathcal O((n+m)\log n)\) 的。
「CF802O」April Fools' Problem (hard)
wqs 二分,里面就不管 \(k\) 的限制了。考虑每一次可以做的事情是什么,要么让当前的 \(b\) 和之前的一个 \(a\) 匹配,要么换掉之前匹配的一个更劣的 \(b\),发现这两种都可以直接放进一个堆里维护,就做完了。然而有 \(\mathcal O(n\log^2n)\) 直接模拟费用流的高论。膜拜。
「CF280D」k-Maximum Subsequence Sum
诚然本题是闵可夫斯基和板题可以直接做,但是有一个更加厉害的做法,直接线段树模拟费用流的求法。连续 \(k\) 次找到区间的最大子段和并将这一段乘以 \(-1\),并把最大子段和加到贡献上,如果最大子段和为负数直接跳过。感觉还是比较厉害的,跑得比闵可夫斯基和快多了。
「ABC270Ex」add 1
想到状态的定义就做完了。但是感觉还是有点难想到。对于某一个状态 \((C_1,C_2,\dots,C_n)\) ,考虑用 \(\max\limits_{i=1}^n\{A_i-C_i\}\) 来表示状态,那么转移就非常好刻画了。
「AT_asaporo2_F」Unicyclic Graph Counting
不做这个题我都快忘了 Prüfer 序列是啥了。考虑把环缩成一个点。那么容易知道每种点在 Prüfer 序列中的出现次数。那么 dp 计算阶乘的系数就可以了。用 E_firework 的话说就是,不会做就是对 Prüfer 序列理解不够深刻。
「JOISC2020」カメレオンの恋
有一个 \(\mathcal O(n^2)\) 次操作的做法就是两两询问,把结果为 \(1\) 的两个连边。那么可以通过 \(O(n)\) 次操作由这个图得到答案。然后优化得到这个图的方式。我们每一次求出独立集,然后找到所有集合外和集合内的连边。这个可以二分。然后再把独立集删掉,重复上述过程。可以证明操作次数是 \(\mathcal O(n\log n)\) 的。
「NOI2021」庆典
整道题唯一一个难点就是看出强连通分量缩点后连通性可以用一棵外向树来表示。然后随便乱做就可以了,比如虚树或者其他东西之类的。史上最水 NOI D1T3 实锤了。
「AGC039E」Pairing Points
好牛啊。考虑定义 \(f_{l,m,r}\) 表示只考虑 \(l\) 到 \(r\) 区间内互相连边,并且要求 \(m\) 已经向外连边,此时的连边方案数。容易发现至少要有一条边横跨 \(m\),那么考虑钦定 \(x\) 和 \(y\) 连边横跨 \(m\) 并且是离 \(m\) 最远的一组横跨 \(m\) 的边。然后再钦定 \(l_0\) 和 \(r_0\) 划分与 \(m\) 与 \(x\) 和 \(y\) 的连通性。那么就可以分成三个子问题了。只不过是 \(\mathcal O(n^7)\) 的。但是常数很小足以通过。