做题记录

【N】新本格魔法少女

好题分享

1月6日好题分享-安师大附中 - Virtual Judge

P11365 [Ynoi2024] 新本格魔法少女りすか - 洛谷

记录详情 - 洛谷

这是一道卡常分块题。

直接对序列分块,则计算贡献分为如下情况:(不妨设块长为 \(B\)

  • 散块对散块:直接用树状数组统计顺序对,复杂度 \(O(nB\log n)\)
  • 整块对其他:因为该题空间较小,所以考虑逐块处理。讨论第 \(i\) 块对答案的贡献时,可以扫描线 \(j\) 维护第 \(i\) 块与前缀 \(j\) 产生的贡献。维护时可以考虑开桶后缀和。加到答案上时要容斥一下。后缀同理。复杂度 \(\displaystyle O(\frac{n^2}{B})\)

平衡后,总复杂度为 \(O(n\sqrt{n\log n})\)。如果使用压位树状数组,那么复杂度可以写成 \(O(n\sqrt{n(\log n-\log w)})\)

压位 BIT

为了卡常,本题使用了压位树状数组。它基于一个性质:

  • 维护的数组值域很小

这个方法能让树状数组单点修改查前缀和的复杂度变为 \(\displaystyle O(\log\frac{n}{w})\),即 \(O(\log n-\log w)\)

例如,维护的数组值域为 \(\{0,1\}\) 时(本题),可以把每 \(w\)\(w=64\))个数组的位置分为一组,用树状数组维护它们的,并且还要维护每组每个位置的值,可以用二进制数,来支持区间查询掩码 + \(O(1)\) popcount)。

BIT 清空减枝

加速树状数组清空的方法好用的有如下两个。

首先,是把所有操作记录下来,单次操作记录时空复杂度为 \(O(1)\)

清空时,把操作经过的位置清零,但是,有如下减枝:

  • 当一个位置已经清零时,直接退出

这使得清空复杂度变为 \(O(\min(n,q\log n))\)\(n\) 为数组大小,\(q\) 为操作次数)。

正确性证明可以考虑把清空弱化为减法

下面是代码:

Tp c[SIZE1]; int N;
int mem[SIZE2], mcnt;
void clear() {
	for (int i = 1; i <= mcnt; i++) {
		for (int it = mem[i]; it <= N; it += it & -it) {
			if (c[it] == 0) break;
			c[it] = 0;
		}
	}
	mcnt = 0;
	return ;
}

其次还有个办法,就是记录每个位置最后一次被更新的时间,如果这个时间少于清空的时间,则清空这个位置。清空的复杂度为 \(O(1)\)。不过慢一些。


实际上,暴力 \(O(n)\) 清空 BIT非常快速的。所以为了卡常,可以在操作次数大于 \(T\) 时暴力单次 \(O(n)\) 清空。

在本题中,\(T\) 可以是 \(650\)

C++98 的速度

在本题中,C++98 的速度薄纱 C++20 的。可能在一些 OJ 上可以用这个来卡常。

【N】Decinc Dividing

好题分享

1月6日好题分享-安师大附中 - Virtual Judge

Decinc Dividing - 洛谷

Problem - 1693D - Codeforces

Submission #300005583 - Codeforces

一道 dp 题。做法高度依赖 dp 值域的性质。

这题要对合法的区间 \([l,r]\) 计数,而合法的区间是能划分为上升子序列下降子序列的区间,发现当 \(l\) 被固定时,合法的 \(r\)一段区间,而且 \([l,l]\) 合法,所以可以考虑求出所有 \(l\) 的最大的 \(r\)

\(f_{i,j}\) 表示区间 \([l,i]\)\(a_i\) 被划分到上升子序列中,下降子序列的最后一个数为 \(j\),能否合法。也对称的设 \(g_{i,j}\)。对于一个区间 \([l,r]\),复杂度是 \(O(n(r-l+1))\) 的。

因为 dp 值都是布尔值,所以考虑在 dp 值上记录更多信息。发现对于 \(f_{i,j}=\text{true}\) 的情况,对于一个 \(i\),希望 \(j\) 越大越好,所以可以重定义 \(f_i\) 表示区间 \([l,i]\)\(a_i\) 被划分到上升子序列中,下降子序列在合法的情况下,最大能是多少。\(g_{i,j}\) 同样这么重定义。这样对于一个区间 \([l,r]\),复杂度为 \(O(r-l+1)\)

容易发现,极大合法区间 \([l,r]\)\(r\) 随着 \(l\) 单调不降,所以考虑双指针发现 \(f_i\)\(l\) 变化的情况下,可能的值只有 \(O(1)\) [1] 。所以可以暴力更新 dp 数组,不过,当没有产生变化时,直接减枝。最后复杂度就是 \(O(n)\) 了。

因为该题的限制很严,所以可以感受出性质 [1]。若要证明其正确性,可以考虑最大的 \(j\) 满足 \(j<i\)\(a_{j}>a_{j+1}\)。此时,\(a_j\)\(a_{j+1}\) 不能同时在上升序列中,故必有至少一个在下降序列中;而因为 \(j\) 的最大性,其一必然为下降序列的结尾。综合其他较为平凡的情况(如找不到 \(j\)),可得 \(f_i\in\{a_j,a_{j+1},\inf,-\inf\}\)

【H】Graph Weighting

1月6日好题分享-安师大附中 - Virtual Judge

G - Graph Weighting

Graph Weighting Editorial - 洛谷专栏

点双连通分量 + 决策单调性题。

点双连通分量生成树是密切相关的**。首先发现每个点双内边的权值必须相等。

然后,问题就能够被转化为非线性规划问题

发现约束条件中系数相同的项可以分开求解,而系数至多有 \(O(\sqrt n)\) 种。每一类可以用优先队列贪心,因为调和级数,这部分复杂度为 \(O(n\log^2n)\)

把每一类的结果合并时,是 \(\min+\) 卷积。由于合并的一边具有凸性单调性,所以相当于决策单调性优化 dp。总复杂度就是 \(O(n\sqrt n\log n)\)

如果合并使用 smawk 算法,可以做到优秀的单次 \(O(n)\),总复杂度变为 \(O(n\log^2n+n\sqrt n)\)

本题的易错点决策单调性分治时,为了保证决策点的正确性,不能简单的在凸性函数末尾补 \(\inf\),这可能会损坏其凸性。

点双划分边

在本题中,需要算出每个点双的点数边数

虽然可以直接建圆方树,但是有隐式建树的方法。

首先,有如下显然的性质:

  • 一个点可能同时属于多个点双
  • 一条边连接的两点一定属于同一个点双
  • 一条边恰好属于一个点双

然后容易发现:

  • 若将所有点双中深度最小的点剔除,那么每个点恰好属于一个点双

上面等价于把圆方树中所有圆指向其父节点。

于是,就可以用 tarjan 求出所有点如上属于的点双。对于边 \(u\leftrightarrow v\),不妨设 \(\text{deep}(u)<\text{deep}(v)\)\(\text{deep}\) 表示该节点在 dfs 树上的深度),那么该边属于 \(v\) 所属的点双。

有凸性的非线性规划问题

有时,可能遇到如下问题。

你需要最小化目标函数 \(z\):(\(\forall i\)\(f_i\) 是函数,\(x_i\) 是变量,\(n\) 为变量个数)

\[z=f_1(x_1)+f_2(x_2)+\cdots+f_n(x_n) \]

但要满足约束:(\(C\) 是一个常数)

\[\begin{gathered} x_1+x_2+\cdots+x_n=C\\ x_1,x_2,\dots,x_n\geq 0 \end{gathered} \]

但是其满足一个重要性质:\(\forall i\)\(f_i(x)\) 的导数(或差分)随 \(x\) 单调不降。

这使得局部最优解就是全局最优解。

下面,不妨设 \(x_0\)\(f_i(x_0)\)\(\displaystyle\frac{\mathrm{d}}{\mathrm{d}x_0}f_i(x_0)\)(或者 \((\nabla f)(x_0)\))的互相计算是 \(O(1)\) 的。

优先队列贪心

如果变量的值域离散,那么可以考虑使用优先队列贪心。时间复杂度 \(O(C\log n)\)

二分斜率

使用该方法的要求是,\(\forall i\),如果知道 \(\displaystyle\frac{\mathrm{d}}{\mathrm{d}x_0}f_i(x_0)\),能快速计算 \(f_i(x_0)\)。不妨设这部分时间复杂度为 \(O(T)\)

如果变量的值域连续,则有性质,当 \(z\) 最优时,存在方案使得

\[\frac{\mathrm{d}}{\mathrm{d}x_1}f_1(x_1)=\frac{\mathrm{d}}{\mathrm{d}x_2}f_2(x_2)=\cdots=\frac{\mathrm{d}}{\mathrm{d}x_n}f_n(x_n) \]

设其为 \(k\),则可二分它,然后再判断是否符合其他要求。时间复杂度 \(O(n\log V)\)\(V\) 为导数的取值范围)。

如果变量的值域是离散的,那么就需要在二分斜率后再跑优先队列贪心。因为差分可能有 \(\pm 1\) 的差距。复杂度 \(O(n(\log V+\log n))\)

一边有凸性的 \(\min +\) 卷积。

一边有凸性的 \(\min+\) 卷积可以用决策单调性优化 dp\(\log\) 解决。还有一些相关算法:

  • 闵可夫斯基和:两边都凸,线性。
  • smawk 算法:该问题线性。

四边形不等式

下文中的 \(+\) 可能不是传统意义上的加法。

\(a<b\),则定义 \(a\) 优于 \(b\)


定义:如果二元函数 \(w(x,y)\) 满足 \(\forall x_1\leq x_2\leq x_3\leq x_4\)

\[w(x_1,x_3)+w(x_2,x_3)\leq w(x_1,x_4)+w(x_2,x_3) \]

那么称其有四边形不等式性。

也可以写为:

\[\begin{gathered} \forall x<y\\ w(x,y)+w(x-1,y-1)\leq w(x-1,y)+w(x,y-1) \end{gathered} \]

或者写成差分形式:

\[\nabla_x\nabla_yw(x,y)\leq 0 \]


区间包含单调性的定义:若函数 \(w(x,y)\) 满足 \(\forall x_1\leq x_2\leq x_3\leq x_4\)

\[w(x_2,x_3)\leq w(x_1,x_4) \]

则称其有区间包含单调性。

实际上,这相当于

\[\left\{ \begin{gathered} \nabla_xw(x,y)\leq 0\\ \nabla_yw(x,y)\geq 0 \end{gathered} \right. \]


可能平凡性:下面几个关于 \(x,y\) 的函数都满足四边形不等式

  • \(C\)\(C\) 是常数)
  • \(f(x)\)\(f\) 是一个函数。也有对称结论 \(g(y)\))。
  • \(f(x)+g(y)\)\(f\)\(g\) 都是函数)

而且它们在四边形不等式中一定取等


可进行线性运算性:对于满足四边形不等式的函数 \(w_1(x,y),w_2(x,y)\)

\[k_1w_1(x,y)+k_2w_2(x,y)+C \]

(其中 \(k_1,k_2\geq 0\)\(k_1,k_2,C\) 均为常数)也满足。


与单调凸函数复合

这里的凸指的是导数单调不降。

\(h(x)\) \(w(x,y)\) \(h(w(x,y))\)
单调不降,凸 区间包含单调性,四边形不等式 区间包含单调性,四边形不等式
区间包含单调性,四边形恒等 四边形不等式

没有找到比较牛的证明。可以使用偏导感性理解。没有完成的证明 - Note.ms 末尾有证明 - OI Wiki

决策单调性优化 dp 的取点问题

分治二分队列求解策单调性优化 dp 问题时,如果有多个同样优的决策点,应该取那个呢?

实际上,可以将决策点的位置作为第二关键字来比较决策点是否优,这样就能避免这种情况(有多个同样优的决策点)的发生。

通常而言,我们会

  • 取最左边的决策点
  • 或取最右边的决策点

这都是对的。

这个做法是错误的:无规则地取决策点。

【E】跳棋 draughts

模拟赛的题。

2025oifc2025.01.09 - 信友队

发现限制很奇怪,而且是从左往右跳。然后就能发现性质,如果不管左右边界,那么奇偶性相同的跳跃位置单调不降。证明可以直接用其定义式。

于是用线段树和分讨就能做到 \(O(n\log n)\)

有一个小技巧,可以二分第一个到达 \(L\) 的跳跃,因为可以直接硬算到底,然后判断是否超过 \(L\)

【N】套娃

模拟赛的题。

2025oifc2025.01.08 - 信友队

发现两个性质:

  • 合并的两个区间值域不交
  • 是否可以合并,具有子序列包含单调性

然后可以推广出一个结论:

  • 如果存在大小关系为 \(2,4,1,3\) 之类的子序列,则该区间一定不可能被合并。其实这还是充要条件。

然后用 rmq值域 BIT 维护每个左端点的最长可合并区间,对于查询,预处理倍增数组即可。最终复杂度 \(O(n\log n)\)

【N】挑战 NPC III

来自好题分享。

1月7日好题分享-常州中学 - Virtual Judge

P9036 「KDOI-04」挑战 NPC Ⅲ - 洛谷

记录详情 - 洛谷 | 计算机科学教育新生态

搜索题

先把重边去了。

首先,将题意转化为

  • 对大小为 \(k\)点覆盖计数

然后,考察度数较大的点,发现性质

  • 度数大于 \(k\) 的点必须选

然后,把这些点删掉,剩下的点的度数每个不超过 \(k\);选一个点最多覆盖 \(k\) 条边,最多选 \(k\) 个点,于是最多有 \(k^2\) 条边

然后,设计一种搜索,在 dfs 的每一层都至少选一个点,这样搜索深度就不超过 \(k\)。然后复杂度就是 \(O(\mathcal{T}(k)\operatorname{poly}(k))\)\(\mathcal{T}(k)=2\mathcal{T}(k-1)+\mathcal{T}(k-2)\))。

需要注意的是,搜索的终点要算组合数,否则就是 \(O(\) 答案 \()\) 的复杂度了。

【E】Łamigłówka

来自好题分享。

1月10日好题分享-学军中学 - Virtual Judge

P9262 [PA 2022] Łamigłówka - 洛谷

记录详情 - 洛谷

首先,进行 \(O(1)\) 次操作让方格到上。

然后维护它在哪个角,而暂不真的进行操作。这样就能让操作简化为转圈了。

发现每转一圈形状不变,但是把方格进行了置换

直接求出置换,然后把每个置换环转几下就做完了。

复杂度 \(O(nm+k)\)

如果后边置换的部分用倍增,那么复杂度为 \(O(nm\log k)\)

小心转置换环不要写挂。

【H】Histogram Rooks

F - Histogram Rooks

Submission #61526564 - AtCoder Grand Contest 041

[AGC041F] Histogram Rooks - 洛谷

一道爆标计数题,需要对容斥有清醒的认识。

首先把广义笛卡尔树 \(O(n^2)\) 建了。

直方图刨分(来自 lsj2009)

广义笛卡尔树(来自 lsj2009)

放棋子的方案合法的充要条件为:

  • 每一列的每一格都能被棋子控制。

为了方便计数,我们记录如下状态:

  • 恰好属于集合 \(S\)最后是放棋子的。

树形 dp 时,设这一小行长度为 \(L\),属于 \(S\) 的列的个数为 \(t\),则我们希望贡献为

\[\begin{cases} 2^L & (t=0)\\ 2^{L-t}-1 & (\text{otherwise}) \end{cases} \]

但是这不能保证剩下的 \(L-t\) 列中一定有棋子,所以考虑容斥,再钦定 \(u\) 行是空的。

dp 是,我们记 \(f[i][j][0/1]\) 表示在 \(i\) 节点,有 \(j\) 列因为某种原因是空的(属于 \(S\) 集合或被钦定),是否全是钦定的列。

需要注意的是,要把容斥系数直接放入 dp 中。

因为树上背包复杂度是 \(O(n^2)\) 的,所以这题可以做到 \(O(n^2\log n)\) 的复杂度。

广义笛卡尔树和直方图刨分

见上。

树上背包复杂度

由于每两个点之间至多合并 \(O(1)\) 次,所以复杂度为 \(O(n^2)\)\(n\) 为树的节点个数)。

实现时,要写上下界优化。

容斥是用来干什么的

容斥本来的作用是

  • 放宽问题的某些限制

但是它会带来糟糕的

  • 容斥系数更多计数问题(例如,需要计算更多集合的大小来算出一个集合的大小)。

所以贪心的来讲,能不容斥就不容斥。

不过容斥还能带来一个附加好处

  • 让某些限制变严

有时候,更严的限制反而更好计算。不过,如果单纯的为了得到这一好处,应该选择直接

  • 增加状态

通常它只会带来复杂度的增加这一坏处。

【E】Odd Mineral Resource

主席树哈希题或者树上莫队分块题。

Problem - 1479D - Codeforces

主席树 Submission #300625666 - Codeforces

莫队 Submission #300784140 - Codeforces

Odd Mineral Resource - 洛谷

主席树的做法简简单单。时间复杂度 \(O(n\log n)\)

莫队做法的话,如果使用树状数据结构维护,时间复杂度将多一个 \(\log n\),会被卡掉。所以,要使用分块平衡复杂度

实际上,只需要开一个,维护每个值出现次数是否是奇数,并且对桶分块,维护每个块出现次数是奇数的值的个数即可。

最终复杂度 \(O(n\sqrt n)\)

主席树的准确空间

在本节中,主要探讨递归建树时,线段树的节点数和深度与维护数组大小的关系。

建树的代码如下:

  • 函数 \(\text{build}(l,r)\)
    • 新建一个节点
    • 如果 \(l<r\)
      • \(\displaystyle \text{mid} = \lfloor\frac{l+r}{2}\rfloor\)
      • 递归调用 \(\text{build}(l,\text{mid})\)
      • 递归调用 \(\text{build}(\text{mid}+1,r)\)

在本节中,默认要维护的数组为 \(a[1],a[2],\dots,a[n]\),一个节点所维护的数组为 \(a[l],a[l+1],\dots,a[r]\)

长度定理:对于线段树的一个节点,若其代表线段的长度为 \(\text{len}\)\(\text{len}=r-l+1\)),则其左儿子代表线段的长度为 \(\displaystyle \lceil\frac{\text{len}}{2}\rceil\)右儿子代表线段的长度为 \(\displaystyle \lfloor\frac{\text{len}}{2}\rfloor\)

节点数猜想:线段树的节点个数为 \(2n-1\).

详情:设节点数为 \(\text{cnt}(n)\),则可得 \(\text{cnt}(1)=1\)\(\displaystyle \text{cnt}(n)=\text{cnt}(\lceil\frac{n}{2}\rceil)+\text{cnt}(\lfloor\frac{n}{2}\rfloor)\),可以使用程序 \(O(n)\) 验证。实际上,当 \(n\leq {10}^8\) 时,该猜想正确。感觉这个猜想应该时对的,可能归纳可以证明。

树高猜想:线段树的树高为 \(\lceil\log_2 n\rceil+1\). 设树高为 \(h(n)\),则 \(\forall i<j\)\(h(i)\leq h(j)\)

详情:有 \(h(1)=1\)\(\displaystyle h(n)=\max\{h(\lceil\frac{n}{2}\rceil),h(\lfloor\frac{n}{2}\rfloor)\}+1\)。也可以 \(O(n)\) 验证。实际上,当 \(n\leq 10^{8}\) 时,该结论成立。


下文中,默认主席树只有单点修改操作。设修改次数为 \(q\)

主席树推荐空间:为 \(\text{cnt}(n)+qh(n)\),即为 \(2n+q(\lceil\log_2 n\rceil+1)\)。不过很多地方都推荐开 \(32n\)\(40n\).

卡满主席树空间:每次修改都修改 \(a[1]\) 即可。这基于上文的树高猜想

树上莫队(伪)

如果是子树查询,则可将树变为 dfs 序,如果是路径查询,则可将树变成括号序

如果是括号序,就需要在指针扫描时,记录一个节点在区间中出现了几次,如果是偶数次,则相当于 \(0\) 次。有的时候还需要暂时添加。

由于 lca 的特殊性,查询区间时要分类讨论。设节点 \(i\) 的左括号位置为 \(F(i)\),右括号位置为 \(L(i)\),则对于 \(x,y\) 路径的查询:

  • \(F(x)\leq F(y)\)
  • \(\text{lca}(x,y)=x\)
    • 查询区间为 \([F(x),F(y)]\)
  • 否则
    • 查询区间为 \([L(x),F(y)]\) \(\text{lca}(x,y)\) 所在位置。

【N】A Independent Set

D - A Independent Set

Submission #61660677 - AtCoder Grand Contest 066

[AGC066D] A Independent Set - 洛谷

A Independent Set 题解翻译 - 洛谷专栏

一道“小贪心” dp 题。

为了防止分讨,令 \(S[n]=\texttt{B}\).

考虑对 \(S\) 操作后得到的串 \(T\),如果操作方式是最优的,那么 \(T\) 一定能被划出若干个段

\[[l_1,r_1],[l_2,r_2],\dots,[l_k,r_k] \]

满足 \(\forall i\)\(T[l_i:r_i]=\texttt{ABAB}\cdots\texttt{AB}\)不属于任何一段的字符一定是 \(\texttt{B}\)

然后,又能发现一个性质,用以序列划分 dp

  • \(\forall i\)\(T[l_i:r_i]\) 的字符均来自于 \(S[l_i:r_i]\)

那么,考虑如何计算 \(S[l:r]\) 变为 \(T[l:r]\) 的代价。设序列 \(X\) 的前缀和为 \(\text{pre}\),则能发现,将 \(i\) 位置的字符挪动至 \(j\) 位置所花费代价为

\[|\text{pre}(i)-\text{pre}(j)| \]

又发现,可以使用转移方式使得绝对值正负性不变。于是,使用一些杂乱的线性技术可做到 \(O(n)\)

“最优值易算”现象

该题目中出现了一个现象,就是,当使用最优子结构转移 dp 时,区间的贡献变得易于计算了(没了绝对值)。

这可能是一个常见的现象。

一个其他领域的例子是,高中物理机车启动问题中,机车功率不变时,当时间最优(速度最大)时,车速是多少。实际上,速度最大值比任意时间速度好算很多。

【E】BFS Trees

简简单单图论小计数。

Problem - 1495D - Codeforces

Submission #300926394 - Codeforces

[AGC067D] Unique Matching - 洛谷

考虑对于每两个点 \(x,y\) 求一次答案。

首先,有性质

  • \(x\)\(y\) 间的最短路唯一,否则答案为 \(0\)

然后先把最短路当作树边。

然后,不妨先将所有剩下的边拆成两条有向边,对于所有边 \(u\to v\),满足(\(d\) 为距离函数)

\[\begin{cases} d(x,u)+1=d(x,v)\\ d(y,u)+1=d(y,v) \end{cases} \]

的话,就把他当成树边。

正确性显然。容易做到单次 \(O(m)\)。总复杂度为 \(O(n^2m)\)

【N】Unique Matching

dag 形递归计数题。难点在于如何找到可递归的结构。

使用任意模数一定程度上“卡掉”了分治 NTT,放过了暴力。

D - Unique Matching

Submission #61676449 - AtCoder Grand Contest 067

[AGC067D] Unique Matching - 洛谷

zhiyin123 的题解:AT_agc067_d [AGC067D] Unique Matching - 洛谷专栏

反向思考

对于有很强对称性的题(如置换问题线性规划问题网络流问题等),如果一种想法失败了,其对偶的想法可能很有前途。

难度变更

难度降级一次。

【E】Qingshan and Daniel

诈骗题。

Problem - 1495E - Codeforces

Submission #301074016 - Codeforces

Qingshan and Daniel - 洛谷

首先,确定一个必输队,然后,对于必输队的每一张牌,执行操作

  • 找到离他最近的异队牌,删掉。

最后就是答案。

该做法的正确性证明很简单。

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

另外,这题不是模拟题

【N】LIS and Inversion

纯粹的 dp 题。

E - LIS and Inversion

Submission #61719813 - AtCoder Regular Contest 180

[ARC180E] LIS and Inversion - 洛谷

发现没思路,于是直接 dp。但是也不好做,不妨只研究代价为 \(0\) 的情况。设 \(f[i][j]\) 表示,\(i\) 的排列,代价用长为 \(i\)\(a\) 的前缀计算,其中一个上升子序列的末尾有 \(j\) 个数比它大。

于是写出转移

\[f[i][j]=\max \begin{cases} \max\limits_{k\geq j} f[i-1][k] & (j\geq a_i)\\ f[i-1][j-1] & (j-1\geq a_i)\\ f[i-1][j] \end{cases} \]

通过贪心单调性,将转移简化为

\[f[i][j]=f[i-1][j]+[j\geq a_i] \]

然后,贪心整体 dp 就能解决此问题了。

实现精细复杂度 \(O(n)\),粗糙为 \(O(n\log n)\)

基于算法结构的思考

一个很常见的思考方式是

  • 直接套上一个算法(常见的有 dp搜索线段树分块等),然后思考和优化。

在没思路是可以尝试。

【N】Squares

数据结构维护最短路题。

Problem - 1495F - Codeforces

扫描线做法 Submission #301226041 - Codeforces

“广义”线段树做法 Submission #301312949 - Codeforces

Squares - 洛谷

首先,通过考察询问产生的变化,把问题转化为

  • \(O(q)\) 次任意两点之间最短路。可以离线。

然后,发现 B 类边越过的区间不交。(使用一些简单的不等式容易证明)

于是,就可以使用

  • 扫描线 + 数据结构

维护了。能做到 \(O(n\log n)\)

也可以把区间形成的线段树建出来,然后使用 lca 等技术完成求解。时间复杂度为 lca 复杂度。

给一些区间建线段树

方法一:使用递归建树。对于所有区间 \([l,r]\),建立点 \(l\) 和点 \(r\),并连边 \(l\to r\),然后就可以快速跨国一个区间了。使用一些手段可以做到线性。

方法二模拟递归建树。把所有区间以 \((l,-r)\) 为关键字升序排序,然后用栈来维护森林的根。容易做到 \(O(n\log n)\),不过也能做到线性。

【H】Three View Drawing

神秘 ad-hoc 构造题。

E - Three View Drawing

Submission #61743887 - AtCoder Regular Contest 175

[ARC175E] Three View Drawing - 洛谷

这题和拉丁方阵有关。

如下图构造

和*拉丁方阵*相关的构造

【N】Subset Trick

数据结构题。

Problem - 1500E - Codeforces

Submission #301381212 - Codeforces

Subset Trick - 洛谷

首先,将 \(S\) 从小到大排序。

通过一些转化,题目变成求一些区间的的大小。

发现区间是否交叉具有凸性对成性(不等式易证)。然后就可以拆贡献算了。

最后复杂度 \(O(n\log^2n)\)

其中有个细节,凸包的顶端为对称轴,所以不需要三分。

【H】Avoid Boring Matches

借助了全局最劣解进行的贪心

E - Avoid Boring Matches

Submission #61763990 - estie Programming Contest 2023 (AtCoder Regular Contest 169)

[ARC169E] Avoid Boring Matches - 洛谷

首先,判掉无解情况。(\(\texttt A\)\(\texttt B\) 少)

对于确定的 \(S\),使用贪心法从左到右确定第一轮的配对情况。

然后,通过交换归纳的方法说明:

  • 局部最劣解就是全局最劣解

然后,在用类似的方法找到全局最劣解 \(T\)

为了计算答案,把 \(\texttt A\) 刻画成 \(-1\)\(\texttt B\) 刻画成 \(1\),然后,要求 \(S\) 的每一个前缀和大于(非严格)对应 \(T\) 的。

因为每次交换差分都会让仅一个前缀和增加 \(2\),所以答案就容易计算了。

通过最劣解判断

在判断性问题中,可以使用全局最劣解判断其他解是否合法。

实际上,这是一种贪心思想。

交换差分模型

这是一个小练习。


给定长度为 \(n\) 的序列 \(a\)\(b\),其中 \(\forall i\)\(a_i,b_i\in\{-1,1\}\)。你需要对 \(a\) 进行尽可能少的操作,使得

\[\forall m,\sum_{i=1}^ma_i\geq \sum_{i=1}^m b_i \]

一次操作形如:

  • 选定正整数 \(i\),交换 \(a_i\)\(a_{i+1}\)

仅需求出最小操作次数。


解法:首先,使用极端法判断是否有解。

然后,考虑一次有效的操作能使得恰好一个前缀增加 \(2\),所以答案为

\[\frac{1}{2}\sum_{m=1}^n\max\{0,\sum_{i=1}^mb_i-\sum_{i=1}^ma_i\} \]

使用前缀和算法可以 \(O(n)\) 完成。

【E】摸爬滚打

模拟赛题。一道广义容斥题。

2025oifc2025.01.03 - 信友队

首先,有一种暴力算法,枚举每一条路劲 \(\text{path}\in P\),其长度为 \(\text{len}\),则答案 \(\text{ans}\) 为:

\[\text{ans}=\frac{1}{|P|\binom{m}{k}}\sum_{\text{path}}\binom{m-\text{len}}{k} \]

难以利用 \(k\) 较小的性质。

考虑广义容斥,钦定路径中有 \(i\) 条损坏,则有

\[\text{ans}=\frac{1}{|P|\binom{m}{k}}\sum_{i=0}^k(-1)^i\binom{m-i}{k-i}\sum_{\text{path}}\binom{\text{len}}{i} \]

\(\displaystyle \sum_{\text{path}}\binom{\text{len}}{i}\)\(\displaystyle [x^i]\sum_{\text{path}}(x+1)^{\text{len}}\),可以背包 dp 计算。

复杂度 \(O(nk)\)

随机 dag 期望路径条数

据说是

\[\exp(\frac{m}{n}) \]

(其中 \(n\) 为点数,\(m\) 为边数)

不知道对不对。反正不多。

本题就放过了 \(O(\) 路劲数 \(\times \operatorname{poly}(n,m,k))\) 的做法。

多项式方法求组合数

因为 \(\displaystyle \binom{n}{i}\)\([x^i](x+1)^n\),所以处理组合数可以使用背包 dp

主要好处为,该式子可以接受一定程度的变形,如 \(\displaystyle \sum \binom{n}{i}\) 之类。

【E】Clues

结论板子题。

Problem - 156D - Codeforces

Submission #301605373 - Codeforces

Clues - 洛谷

一些有关树的结论

一些有关树的结论【随机树树高】【完全图生成树个数】【连接连通块方案数】【Prüfer 序列】【Prufer 序列】 - 洛谷专栏

【N】独脚大盗

模拟赛题目。prufer 序列相关的计数 + lagrange 插值

2025oifc2025.01.03 - 信友队

\(f[n][m]\) 表示大小为 \(n\) 的图中,边权值域为 \([1,m]\) 的答案。然后,就能写出 \(O(n^3m)\) 的类似于多项式 expdp 转移。

然后,发现 \(f[n][m]\) 是关于 \(m\) 的多项式,于是,直接 lagrange 插值

能做到 \(O(n^5)\)

下面是一些公式

\[\begin{gathered} \left(\sum_i s_i\right)^{k-2}\prod_i s_i\\ f[n][m]=f[n][m-1]+\sum_{\sum_{i}s_i=n}n^{k-2}\prod_if[s_i][m-1]\binom{s_1+s_2+\cdots+s_i-1}{s_i-1}s_i(M-m+2)^{s_i(s_1+s_2+\cdots+s_{i-1})-1}\\ g_m[n][k]=\sum_{i=1}^{n-1}g_m[n-i][k-1]f[i][m-1]\binom{n-1}{i-1}i(M-m+2)^{i(n-i)-1}\\ g_m[n][1]=f[n][m-1]n\\ f[n][m]=f[n][m-1]+\sum_{k=2}^nn^{k-2}g_m[n][k] \end{gathered} \]

lagrange 插值

lagrange 插值笔记 - 洛谷专栏

lagrange 插值做题记录 - zhiyin123123 - 博客园

【E】2-Coloring

简单计数题。

Problem - 1503E - Codeforces

Submission #301942015 - Codeforces

2-Coloring - 洛谷

2025.01.20 练习 - zhiyin123123 - 博客园

2021 年的题很老吗?怎么 *3100 这么简单?

发现染色合法的充要条件为,蓝色或黄色构成上下或左右两个凸包形。

使用一些对偶、前缀和等技巧可以轻松 \(O(n^2)\)

【H】Large DP Table

需要观察性质的数据结构题。

F - Large DP Table

Submission #61900640 - estie Programming Contest 2023 (AtCoder Regular Contest 169)

[ARC169F] Large DP Table - 洛谷

Large DP Editorial【翻译】 - zhiyin123123 - 博客园

2025.01.20 练习 - zhiyin123123 - 博客园

怎么 codeforces div.1 还没 arc 难啊?

先把 dp 理解成每个点 \((i,j)\) 走到 \((1,1)\) 的最优方案权值和。

需要观察到一个重要性质

  • 对于子矩形 \(R(a,b)\)(表示所有 \(a\leq i,b\leq j\)\((i,j)\) 构成的矩形),能判断方格 \((c,d)\)\((c,d)\in R(a,b)\)是横着走出 \(R(a,b)\) 还是竖着走出 \(R(a,b)\)。横着走出当且仅当 \(\displaystyle \min_{a\leq i\leq c}A_i<\min_{b\leq j\leq d}B_j\)

然后,就可以使用差分笛卡尔树单调栈等东西做到 \(O(n)\) 了。

单调栈建立笛卡尔树

维护右链即可,和虚树的建立相似。可以做到线性。

笛卡尔树 - OI Wiki

笛卡尔树优化并查集

问题描述

给定长度为 \(n\) 的排列 \(P\),请求出 \(k\) 取边 \(\{1,2,\dots,n\}\) 是的答案。

  • 找出所有 \(P\)极长连续段(假设有 \(t\) 个)\([l_1,r_1],[l_2,r_2],\dots,[l_t,r_t]\),满足 \(\forall i\)\(\forall j\in[l_i,r_i]\),满足 \(P_j\leq k\),则答案为 \(\displaystyle\sum_{i=1}^t f(l_i,r_i)\)。其中,\(f(x,y)\) 为交互库中给出的函数,调用次数不能超过 \(5n\) 次。

解说:用珂朵莉树时间复杂度 \(O(n\log n)\)并查集时间复杂度 \(O(n\alpha(n))\)笛卡尔树时间复杂度 \(O(n)\)。不过,函数调用次数都是 \(O(n)\) 的。

【E】Tree Calendar

关于 dfs 序的简单性质题。

2024.01.21 practice - zhiyin123123 - 博客园

Problem - 1508E - Codeforces

Submission #302196117 - Codeforces

Tree Calendar - 洛谷

发现多次操作相当于不断把根放在 dfs 序最小的叶子上,并删除这个叶子,剩下的节点仍保持 dfs 序

然后,做法就有了。首先,直接按照 \(A[i]\) 给每个节点的儿子排序,方便以后处理。

首先,找到“根到叶子”操作是否只做了一半。如果只做了一半,就暴力 \(O(n)\) 把根复位,并计入答案。做这个的同时可以判断没有被删除的节点是否符合 dfs 序。不过,根只能在左链上。

然后,被删除的叶子应该是出栈序,直接判断即可。需要注意的是,这个出栈序是连续的,不能是多个出栈序拼起来。

能做到 \(O(n)\)。用 std::sort 则是 \(O(n\log n)\)

【H】One Square in a Triangle

神秘平面几何构造题

2024.01.21 practice - zhiyin123123 - 博客园

E - One Square in a Triangle

Submission #61932714 - AtCoder Regular Contest 167

[ARC167E] One Square in a Triangle - 洛谷

对于 \(S\) 是偶数的情况非常简答,一眼丁真可得

  • \(S=2\) 时无解。
  • 其他情况取 \(\displaystyle (0,0),(2,0),(\frac{S}{2},\frac{S}{2})\).

考虑奇数怎么办。先把一个点固定为 \((0,0)\),设剩下两个点为 \((x_1,y_1),(x_2,y_2)\),则有

\[S=|x_1y_2-x_2y_1| \]

发现必须让 \(x_1,y_1\) 一奇一偶,且不能让 \(x_2,y_2\) 同为偶数。不妨先令

\[y_1=x_1+1 \]

\[S=|y_2x_1-x_2(x_1+1)| \]

画图后,发现让 \((x_2,y_2)=(3,1)\) 最适合,因为它能保证 \(S\geq 9\) 时只包含一个正方形

\[S=2x_1+3 \]

不知为什么,\(S<9\)\(S\) 为奇数时无解

来自 樱雪喵 https://www.luogu.com.cn/user/234074

单次复杂度 \(O(1)\)

【N】Inverse Inversions

不错的分块题。

Problem - 1540D - Codeforces

时间 \(O(n\sqrt n\log n)\) 空间 \(O(n)\) 做法:Submission #303225649 - Codeforces

时间 \(O(n\sqrt n)\) 空间 \(O(n)\) 做法:Submission #303312722 - Codeforces

Inverse Inversions - 洛谷 | 计算机科学教育新生态

2025.01.27 practice - zhiyin123123 - 博客园

不妨设题目中给定的数组为 \(A\)

对于题目所给的排名信息(逆序对数)\(A[i]=x\),直接令 \(A[i]=i-x\),这样就是询问的排名了。

对于询问 \(p\),容易打出暴力

  • function \(\text{jump}(p)\)
    • let \(\text{ord}=A[p]\)
    • for \(i\) in \((p+1,p+2,\dots,n)\) do
      • if \(A[i]\leq \text{ord}\) then
        • \(\text{ord}\gets\text{ord}+1\)
    • return \(\text{ord}\)

这样说明答案是唯一的。

发现难以用树形数据结构优化(由于有修改),于是考虑序列分块。

每个块需要维护某个排名跳过该块后会变成什么排名,可以用下面这个暴力算法理解

  • funtion \(\text{solve}(p)\)
    • let 集合 \(S=\{1,2,\dots,n\}\)
    • for \(i\) in \((n,n-1,\dots,p+1)\) do
      • 删除 \(S\) 中第 \(A[i]\) 小的元素
    • return \(S\) 中第 \(A[p]\) 小的元素

使用树状数组(甚至线段树也可以)对每个块构建集合 \(S\) 能做到 \(O(n\sqrt n\log n)\) 的复杂度,需要卡常才能在 turtleforces 上通过。

然后,发现集合 \(S\) 可以线性分裂和归并!于是使用逐块处理基数排序等技巧可以做到 \(O(n\sqrt n)\)

树状数组上倍增(二分)

倍增时,增加的长度恰好是树状数组维护的区间长,所以可以做到优秀的单 \(\log\)

下面是伪代码。

  • BIT 的长度为 \(n\)
  • function \(\text{search}(\dots)\)
    • let \(i=0\)
    • for \(j\) in \((\lfloor\log_2(n)\rfloor,\lfloor\log_2(n)\rfloor-1,\dots,0)\) do
      • let \(s=i\ \text{or}\ (1\ \text{left shift}\ j)\) 注释:其中 \(\text{or}\)按位或
      • if \(s\leq n\) then
        • if 在前缀 \(i\) 的基础上,新增节点 \(s\) 合法 then
          • \(i\gets s\)
    • return \(i\)

块内有序的高效性

\(O(n\sqrt n\log n)\)\(O(n\sqrt n\log n)\) 之间也有区别!设块长为 \(B\),则 \(O(\log n)\)\(O(\log B)\) 常数差距巨大!

在本题中,用树状数组建立集合 \(S\),要将其存在长为 \(B\) 的数组中,这样,二分的时候复杂度就是 \(O(\log B)\) 了,由此块长就可以开的非常小(例如 \(B\)\(90\))。

归并和分裂的复杂度优势

对于合并大小为 \(n\) 和大小为 \(m\) 的对象,有的复杂度为 \(O(n+m)\),有的为 \(O(\min\{n,m\})\),还有的为 \(O(nm)\) 等大复杂度,但是合并通常比逐一合并优秀。

合并和分裂(真的分裂、撤销或回退)互为逆运算,常能单独或结合其他算法产生巨大作用。在本题中,就是将其与分块结合起来。

【N】Fizz Buzz Difference

小清新欧几里得题。

E - Fizz Buzz Difference

\(O(T\log V)\) 的解线性同余不等式做法:Submission #62189079 - AtCoder Regular Contest 166

\(O(T\log^2V)\)二分 + 类欧几里得做法:Submission #62190569 - AtCoder Regular Contest 166

2025.01.26 practice - zhiyin123123 - 博客园

首先,根据贪心思想,\(L-1\)\(R+1\) 一定是 \(a\) 的倍数。于是,就可以通过二分先把 \(R-L\) 求出来。

然后再是确定最小的 \(L\)

  • 方法一:写出 \([L,R]\) 中第一个 \(b\) 的倍数的位置与 \(L\) 的距离 \(d\) 的约束条件,发现它形如线性同余不等式,要求其中的变量最小化。于是可以使用辗转相除算法。
  • 方法二:发现 \(L\) 取任何值时,其中 \(b\) 的倍数的个数的极差不超过 \(1\),而我们要找到第一个值较大的位置,于是,可以直接对前缀和二分,计算前缀和需要使用类欧几里得。可惜复杂度多个 \(\log\)

最小化 \(ka\bmod m\) 问题

给定正整数 \(a,m\)\(a<m\)),你需要最小化 \(ka\bmod m\)\(k\) 可以取 \([L,R]\)\(R<m\))的整数。

怎么做呢?不妨设 \(a\)\(m\) 互质(不互质显然可以规约为互质的情况),则可设

\[y=ka\bmod m \]

\(a^{-1}\)\(a\) \(m\) 意义下的逆元,则

\[k=ya^{-1}\bmod m \]

于是问题就被转化为

\[L\leq ya^{-1}\bmod m\leq R \]

套用下面的欧几里得算法就可以单 \(\log\) 求解了。


另外,这个问题也可以类欧几里得 + 二分做,用了下一节的技巧。

转化为有单调性

有时候,我们需要求序列 \(A\) 中第一个满足性质 \(p\) 的元素。

这时,可行的思路就是,将 \(p\) 转化为对 \(A\) 有单调性的命题。

一般都要与前缀扯上关系。

本题就借助了 \(A\) 仅由 \(\{\text{cnt}-1,\text{cnt}\}\) 构成,于是,可以全局减 \(\text{cnt}\),再二分寻找前缀和第一个大于 \(0\) 的位置。而前缀和的计算恰好可以使用类欧几里得

欧几里得相关算法

欧几里得相关算法【含万能欧几里得】 - zhiyin123123 - 博客园

欧几里得相关算法做题记录 - zhiyin123123 - 博客园

【E】斑斓之地

校内模拟赛题。平面图欧拉定理题。

P3776 [APIO2017] 斑斓之地 - 洛谷

记录详情 - 洛谷

因为

\[V-E+F=C+1 \]

所以直接二位数点求 \(V,E,F\) 就可以了。需要注意的是,统计 \(F\) 时,最外面的面和河流的面既可能联通,也可能不连通。

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

【E】Bitaro's Travel

校内模拟赛题。时间复杂度分析题,和“鱼”类似。

P9342 [JOISC 2023] Bitaro's Travel (Day4) - 洛谷

发现每个询问中,转弯的次数只有 \(O(\log n)\) 次。于是就可以做到 \(O(n\log n\log V)\) 了。

【E】游戏

校内模拟赛题。简单换根 dp 题。

P11627 [迷宫寻路 Round 3] 游戏 - 洛谷

拆贡献 + 换根 dp(线段树或 BIT 维护)

【E】造树据

校内模拟赛题。树哈希 + 换根 dp

P11618 [PumpkinOI Round 1] 造树据 - 洛谷

记录详情 - 洛谷

树哈希 hash

用下面的方法可以 \(O(n)\) 求出无标号有根树 hash。如果需要求无根树的,可以钦定重心为根。这个方法可以 \(O(1)\) 向相邻的节点换根

该方法基于可重集 hash

下面是伪代码。

用数组 \(H\) 记录 hash 值。有常数 \(a,b,c,C_1,C_2\),通常取 \(a=13,b=7,c=17\)\(C_1,C_2\) 随意。

  • function \(f(x)\)

    • \(x\gets x \operatorname{xor}(x\operatorname{leftshift}a)\)
    • \(x\gets x \operatorname{xor}(x\operatorname{rightshift}b)\)
    • \(x\gets x \operatorname{xor}(x\operatorname{leftshift}c)\)
    • \(x\gets x\operatorname{xor}C_1\)
    • return \(x\)
  • function \(\text{dfs}(u,\text{fa})\)

    • \(H[u]\gets C_2\)
    • for \(v\)\(u\) 的子节点 do
      • \(\text{dfs}(v,u)\)
      • \(H[u]\gets H[u]+f(H[v])\)

换根 dp

实际上,很多 dp 都是可以换根的。特别是可以写成合并和分裂贡献的 dp。

相同形态的堆个数

给定一个无标号有根树,要求给每个节点进行标号,使其标号满足堆的性质。则方案数为

\[\frac{n!}{\prod \text{siz}} \]

节点个数所有子树大小之积的比。

【H】Bear and Cavalry

校内模拟赛题。神秘结论题。

P10198 [USACO24FEB] Infinite Adventure P - 洛谷

Problem - 573D - Codeforces

Submission #304658780 - Codeforces

首先,把问题描述成特殊的带权二分图匹配问题。

在没有限制的时候,显然按照能力大小排名匹配能最大化总能力值。

然后,先把人和马按照能力值排序了,发现一个结论,所有的最有配对方式都能由以下四种拼成。(不会证捏

Bear and Cavalry 的配对方法

(可以认为,第一排点代表人,第二排点代表马)

不妨设 \(f_i\) 为只考虑排名前 \(i\) 大的人和马时的答案,然后,可得 \(f_i\) 仅由 \(f_{i-1},f_{i-2},f_{i-3}\) 转移而来。

接着,又发现 dp 可以用 \(\max+\) 矩阵刻画。于是,就可以用线段树维护矩阵数组,在询问时单点修改,做到 \(O(n\log n)\) 的复杂度。

【H】Infinite Adventure P

校内模拟赛题。非常好的倍增题。

P10198 [USACO24FEB] Infinite Adventure P - 洛谷

记录详情 - 洛谷

首先,容易建立分层图并倍增,空间复杂度 \(O(n\max\{T_i\}\log V)\),不可以通过。

我们希望将 \(\max\{T_i\}\) 从复杂度分析中去除。考虑产生 \(\max\{T_i\}\) 主要是因为,倍增数组开的不够大的话,无法正确预处理。

但是,\(T_i\) 相同的城市的倍增数组预处理是正确的。于是,可以将城市分类,\(T_i\) 相同的城市分作一类

然后,就转而设 \(f_{i,j,k}\) 表示从 \(t\) 时刻(\(t\bmod T_i=j\))进入城市 \(i\),向前走,恰好经过 \(2^k\)同层城市后,到达哪个城市。(还有些其他的东西要维护哦)

发现这样就可以 \(O(n\log V)\) 预处理了。

对于查询,设倍增跳跃时经过的城市为关键城市,则关键城市的层数先增大,后减少,经过的层数为 \(O(\log n)\) 层,每层跳跃复杂度为 \(O(\log V)\),所以单次查询复杂度 \(O(\log n\log V)\)

最终复杂度为 \(O((n+Q\log n)\log V)\)

实现有非常多细节可以减少常数。

end 值与倍增(开区间的优点)

可以在数组末尾放置 end 值,并令 end 不属于该数组,可以简化代码实现。下面有几例。

需要明确的时,end 值也可以放在开头,这时本质相同的。实际上,本节可以被认为,在探讨开区间的优点

  • stl 中的算法喜欢用 end() 表示“没有”。
  • 二分时,使用左闭右开区间,方便实现。
  • 树上倍增中,用不属于树的 \(0\) 节点充当“根的父亲”。
  • 本题中,倍增数组末尾放置不满足定义的下一个节点,可以方便实现。

本题则体现了它与倍增的组合。

无穷大限制

若要维护 \([l,r]\cup\{\inf\}\) 中的数,对于 \(\inf\) 的处理,至少有如下几种方式:

  1. 直接维护一个数是否是 \(\inf\)
  2. 钦定一个极大的数作为 \(\inf\)

对于第二种处理方式,为了防止溢出,可以使用如下手段:

  • 实时监测维护的数 \(x\),若 \(x\) 大于 \(\inf\) 的钦定值,直接令 \(x\) 为该钦定值。

这种处理方式也可以用来直接防止溢出。

例如,在本题中,就可以用 \({10}^{18}\) 作为阈值,当倍增数组的辅助数组即将超过它时,则停止倍增。这样可以防止 long long int 溢出。

【E】白兔迷宫

校内模拟赛题。很简单的随机游走题。

白兔迷宫 - QOJ 8947 - Virtual Judge

Source code - Virtual Judge

需要使用高斯消元,做到 \(O(n^3)\)

随机变量的方差

随机变量 \(X\) 的方差 \(\mathbb{D}(X)\) 也满足:

\[\mathbb{D}(X)=\mathbb{E}(X^2)-\mathbb{E}^2(X) \]

一般方差都这么算。


推导:如下定义期望和方差(设 \(X\)\(x\) 的概率为 \(P(x)\)

\[\begin{gathered} \mathbb{E}(X)=\sum_{x}xP(x)\\ \mathbb{D}(X)=\sum_x(x-\mathbb{E}(x))^2P(x) \end{gathered} \]

然后就可以推导

\[\begin{gathered} \mathbb{D}(X)=\sum_x(x-\mathbb{E}(X))^2P(x)\\ =\sum_xP(x)(x^2-2x\mathbb{E}(X)+\mathbb{E}^2(X))\\ =\sum_xx^2P(x)-2\mathbb{E}(X)\sum_xxP(x)+\mathbb{E}^2(X)\sum_xP(x)\\ =\mathbb{E}(X^2)-2\mathbb{E}^2(X)+\mathbb{E}^2(X)\\ =\mathbb{E}(X^2)-\mathbb{E}^2(X) \end{gathered} \]

感觉非常巧合。

随机游走

下文中,对于节点 \(x,y\),不妨用 \(x\to y\) 表示存在从 \(x\)\(y\) 的有向边;对于节点 \(x\),分别用 \(\text{in}[x]\)\(\text{out}[x]\) 表示其入度出度

不平凡的,本节的图不一定是 dag

图以 \(S\) 为起点,\(T\) 为终点。从 \(S\) 开始,每次从所在节点等概率随机选择一条出边,沿着出边前进到下一个节点,直到所在节点为 \(T\)特别的,\(\text{out}[T]=0\)

如何求解所走过的期望路径长度?

期望次数

可以从每个节点被经过的期望次数来列方程。

\(f_i\) 为节点 \(i\) 被经过的期望次数,则可列出方程

\[f_i=[i=S]+\sum_{j\to i}\frac{f_j}{\text{out}[j]} \]

期望长度

警告:未验证该方法是否正确!

也可以设 \(f_i\) 为到达节点 \(i\) 时,所走路径的期望长度。

\[f_i=\sum_{j\to i}\frac{f_j+1}{\text{out}[j]} \]

CEN-Price List

校内模拟赛题。神秘的广度优先搜索 + 三元环题。

P3547 [POI 2013] CEN-Price List - 洛谷

记录详情 - 洛谷

首先,在原图中求出 \(k\) 到所有的 \(i\) 的最短路 \(\text{dis}_i\),则答案(对于 \(i\) 来说)有上界

\[\min\{\text{dis}_i\times a,\lfloor\frac{\text{dis}_i}{2}\rfloor\times b+(\text{dis}_i\bmod 2)\times a\} \]

(由于最短路的最短性,路径中不会连续有三元环的两条边)

除此之外,答案就只可能时 \(b\) 的倍数了。

上面那个上界容易 \(O(m)\) bfs 求出。对于其他情况,显然有 \(O(m^2)\) 的暴力。发现两个相邻的边不能合成一个新边,当且仅当它们在同一个三元环中。于是直接 bfs并在过程中删边,则拓展失败的次数不超过三元环的个数,即 \(O(m\sqrt m)\),于是就有 \(O(m\sqrt m)\) 的做法了。

三元环个数

使用三元环计数的算法就能证明三元环个数是 \(O(m\sqrt m)\) 的。

这里有一个很简洁的证明:

\[\text{Cnt}=\sum_{x\in G}\min\{\text{deg}_x^2,m\}\leq \sum_{x\in G}\sqrt{\text{deg}_x^2m}=O(m\sqrt m) \]

单点删除的实现

维护单点删除有如下常见方法:

  1. 直接删除。形如分裂再合并。例如链表、BST 的删除。
  2. 惰性删除。将其标记为删除,或替换为代表“空”的元素。
  3. 当前弧优化。记录哪些前缀(或后缀、区间)已被删除。
  4. 顶替。使用容器中的其他元素将其顶替。例如 std::vector 的先和 back() 交换,再 pop_back();又例如二叉堆的删除。

【N】Gregor and the Two Painters

非常棒的连通块计数题,需要使用二维数点

Problem - 1548E - Codeforces

Submission #304852603 - Codeforces

Gregor and the Two Painters - 洛谷

对于连通块计数,考虑代表元

用一个有序三元组表示一个格子,对于格子 \((x,y)\),表示为 \((a_x+b_y,x,y)\),不妨令连通块中(字典序)最小的格子为代表元。

发现性质非常强,可以找到“一个格子是代表元”的充要条件使得其非常适合二维数点计算。最终复杂度就是 \(O(n\log n)\)

连通块计数

常见的转化方法有

  1. 拆贡献。例如拆成边数,或者平面图欧拉定理之类。
  2. 代表元。对连通块的代表元计数。

当然,有的时候也可以直接统计连通块个数。

【E】Kevin and Matrices

不错的计数题。需要对偶容斥

Problem - 2048G - Codeforces

Submission #304957783 - Codeforces

Kevin and Matrices - 洛谷

需要依次发现如下性质:

  1. 题目中的不等式不可能取 \(<\)
  2. 题目中的不等式成立,当且仅当存在一个矩阵中的元素 \(a_{x,y}\),不仅是第 \(x\) 行的最大值,而且是第 \(y\) 列的最小值。

然后就是类似于广义容斥原理的写出和式,然后使用二项式定理化简为 \(O(n\cdot v)\) 的式子。

posted @ 2025-01-20 08:37  zhiyin123123  阅读(189)  评论(0)    收藏  举报
目录侧边栏

qwq