<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Algorithms on LunaTide's Blog</title><link>https://lunatide.tech/tags/algorithms/</link><description>Recent content in Algorithms on LunaTide's Blog</description><generator>Hugo -- gohugo.io</generator><language>en-us</language><copyright>LunaTide's Blog</copyright><lastBuildDate>Thu, 16 Oct 2025 00:00:00 +0000</lastBuildDate><atom:link href="https://lunatide.tech/tags/algorithms/index.xml" rel="self" type="application/rss+xml"/><item><title>计算几何专项</title><link>https://lunatide.tech/p/%E8%AE%A1%E7%AE%97%E5%87%A0%E4%BD%95%E4%B8%93%E9%A1%B9/</link><pubDate>Thu, 16 Oct 2025 00:00:00 +0000</pubDate><guid>https://lunatide.tech/p/%E8%AE%A1%E7%AE%97%E5%87%A0%E4%BD%95%E4%B8%93%E9%A1%B9/</guid><description>&lt;img src="https://lunatide.tech/p/%E8%AE%A1%E7%AE%97%E5%87%A0%E4%BD%95%E4%B8%93%E9%A1%B9/codeforce_%E5%89%AF%E6%9C%AC.jpg" alt="Featured image of post 计算几何专项" /&gt;&lt;p&gt;&lt;a class="link" href="https://vjudge.net/problem/POJ-2318" title="POJ-2318"
target="_blank" rel="noopener"
&gt;POJ-2318&lt;/a&gt;&lt;/p&gt;</description></item><item><title>ICPC日常训练01</title><link>https://lunatide.tech/p/icpc%E6%97%A5%E5%B8%B8%E8%AE%AD%E7%BB%8301/</link><pubDate>Thu, 09 Oct 2025 00:00:00 +0000</pubDate><guid>https://lunatide.tech/p/icpc%E6%97%A5%E5%B8%B8%E8%AE%AD%E7%BB%8301/</guid><description>&lt;img src="https://lunatide.tech/p/icpc%E6%97%A5%E5%B8%B8%E8%AE%AD%E7%BB%8301/codeforce_%E5%89%AF%E6%9C%AC.jpg" alt="Featured image of post ICPC日常训练01" /&gt;&lt;p&gt;日常的训练，回顾一下做的几道题，实现不发&lt;/p&gt;
&lt;h2 id="icpc-hangzhou-reginal-f-fuzzy-ranking"&gt;ICPC Hangzhou Reginal F Fuzzy Ranking
&lt;/h2&gt;&lt;p&gt;不太会做，看了一下题解，下面是看完题解后的思路&lt;/p&gt;
&lt;p&gt;直接为任意“前→后”对连边会太多，在同一排列中，只连相邻元素 $a_j\to a_{j+1}$ 即可：因为一条从前往后的有向路径已经能覆盖该排列中任意“前→后”的可达关系。对所有 $k$ 个排列加边&lt;/p&gt;
&lt;p&gt;对图做一次 Tarjan/Kosaraju缩点，得到每个学校所属的 SCC 编号bel[x]，以及按拓扑序逆序排列的分量列表 scc。把每个榜单按 bel重新映射成“分量编号序列”。&lt;/p&gt;
&lt;p&gt;在某个榜单中，原先相邻的两点之间有边，缩点后相同分量的编号在该榜单上必然连成一段。因此每个榜单都可以被切成若干段，每段恰好由同一个 SCC 的元素组成。这个性质让我们可以把任意区间 $[l,r]$ 拆解为：左端一个不完整段 + 中间若干完整段 + 右端一个不完整段。&lt;/p&gt;
&lt;p&gt;对每个榜单i:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Segment：对位置轴进行分段。令 Segment= (L, R) 表示pos所在的那段在该榜单上的左右端点下标。线性扫，遇到一段相同编号的区间 $[L,R]$ 就把这对端点填给其中的每个位置。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;dp 前缀：统计从开头到位置 $j$ 为止、同段内能形成的“模糊对”数量。若 $j$ 落在段 $[L,R]$，新增的成对数等于该段里被纳入的元素个数减一，即 $j-L$。因此定义
&lt;/p&gt;
$$
dp[id][j] = dp[id][j-1] + (j-L).
$$&lt;p&gt;
这样任意区间 $[x,y]$ 的“在同一段内形成的对数”就能通过 $dp$ 差分 $dp[id][y]-dp[id][x]$ 得到。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;总计复杂度$O(nk)$&lt;/p&gt;
&lt;h2 id="cf1841e-fill-the-matrix"&gt;CF1841E Fill the Matrix
&lt;/h2&gt;&lt;p&gt;题目说有一个$n * n$的正方形矩阵，在第$i$列，前$a_i$个格子都是黑色，剩下的格子是白色，在矩阵放入1到m到整数，每个格子最多放一个且黑色格子不能放，定义美丽值为数字 $j$ 和 $j+1$ 位于&lt;strong&gt;同一行&lt;/strong&gt;，且 $j+1$ 位于 $j$ 的&lt;strong&gt;右边相邻的格子&lt;/strong&gt;，求放置m个整数后最大美丽值&lt;/p&gt;
&lt;p&gt;我们一定先选一个最长的白色格子全填进去，直到填满或者数不够。因为如果不继续填等于说最后填的那个数旁边的格子就浪费了，所以关键就在于要把所有行的白色连续横段都计算出来，按长度分组，记为cnt[n]，代表长度n的横段有几个，直接暴力扫迷线维护复杂度是$O(n^2)$的，直接炸了，所以我们用线段树来维护最大值和位置然后再分治来统计cnt数组，相当于构建一颗笛卡尔树，每次把区间按最大值分为左右两部分，统计每层能产生的白格段，最后用贪心计算答案就可以了，这样最后复杂度就控制在$O(nlogn)$&lt;/p&gt;
&lt;h2 id="cf2056d-unique-median-2200"&gt;CF2056D Unique Median 2200
&lt;/h2&gt;&lt;p&gt;给了一个整数数组b，当排序后满足$b⌊\frac{m+1}{2}⌋=b⌈\frac{m+1}{2}⌉$时我们说数组是好的，题目说给一个长度为n的数组a，计算好子数组数量&lt;/p&gt;
&lt;p&gt;首先观察好数组定义，我们可以很容易发现奇数长度的数组一定是好数组，所以我们只要看偶数长度的数组就可以了，很困难，想了一段时间，一开始的想法是如果我们要让偶数的数组是好的，那么当且仅当存在某个数$v$，使得在选取的子数组中$v \ge m/2$，也就是说至少一半都是同一个数，但是肯定会有重复用容斥修正，减掉重复的就可以，实现很麻烦，写了很久，而且还发现是错误的，对于[1,1,2,3]按照这个思路明显错的，而且发现正着处理非常麻烦困难，于是决定反向试试，从所有子数组中减掉&amp;quot;坏的&amp;quot;，再修正&lt;/p&gt;
&lt;p&gt;很快就发现了一些东西，对于一个偶数的数组，只要让排序后第k个数小于k+1个数一定是坏的，再具体点，我们选定两个相邻的数x，y，我们只要让左中位数小于等于x，右中位数大于等于y就可以了，然后用&lt;strong&gt;前缀和+map即可&lt;/strong&gt;，并且小于等于x的数的数量和大于等于y的数字数量必须要一样多，那么我们可以把数组按照值分为3类，一种小于等于x我们记为-1，大于等于y记为+1，介于x和y之间的我们直接清空，因为出现就相当于直接破坏了我们的数组&lt;/p&gt;
&lt;p&gt;最后就是用容斥进行修正，只要x和y相差超过2就记为重复的减掉就可以了&lt;/p&gt;
&lt;h2 id="cf1854a2--dual-hard-version"&gt;CF1854A2 Dual (Hard Version)
&lt;/h2&gt;&lt;p&gt;一道思维题，给了一个数组，可以对于$i,j$的元素进行操作，使得$a_i := a_i + a_j$&lt;/p&gt;
&lt;p&gt;要求在31次操作内让数组不递减&lt;/p&gt;
&lt;p&gt;首先当所有元素都大于等于0或者全部都小于等于0的时候很显然，我们只需要把右边的数依次加上左边的数肯定是对的（小于等于0同理反过来就行）&lt;/p&gt;
&lt;p&gt;所以关键是要看数组里有正有负，我们设最大的正数是mx，绝对值最大的负数是mi，正数数量是cp，负数数量是cm，那么我们有两种选择，一种是都统一成非负，一种是统一成非正，只要符号统一我们就方便了，拿统一非负举例（非正同理），我们其实就是要让最大的正数足够大，能够覆盖所有负数，我们首先计算mx经过几次翻倍可以大于mi，然后让他翻倍，之后让所有的负数都加上这个mx它们都变成正数了，然后我们就判断一下这两种选择哪个更优即可&lt;/p&gt;</description></item></channel></rss>