算法竞赛 套路 or 技巧 or 思路

310 阅读9分钟

来自裆部选手的积累

竞赛图

定义:竞赛图就类似于无向完全图给每条边定义了方向。

题目一

codeforces.com/contest/177…

题意:我们可以选择若干个人和剩下的人比赛,返回赢了多少场。

思路:

定理 1. 竞赛图强连通缩点后的DAG呈链状, 前面的所有点向后面的所有点连边

参考博文:www.cnblogs.com/A-Quark/p/1…

根据这个定理,我们很明显可以把这个图的度数取出来,即只选出某一个人与其他人决斗,得到的场数就是该点的出度,然后按照度数排序,然后根据这个定理,我们找最前面的强连通图即可。

如何判断?

强连通分块内部肯定是相互链接,然后当前的强连通分块一定指向剩下的点。

定理 2.兰道定理 - 判断是否是竞赛图

没有做到考察兰道定理的,但是还是了解为好。

图论

思考方式:强连通 + 简单环 or 简单环

给你一个有向图,想知道从某个点开始,经过若干个点,最后返回这个点的路径 能表示成什么数。[抽象版]

类似于求回路的权值和能表示成什么形式。[一般和模数挂钩]

例题1 atcoder.jp/contests/ab…

题意 给你一个有向图,以及权值10 ^ 10 ^ 100 , 问你能否从1开始走,1结束的路径走完这个权值?

这个题明显是让你求1回路的路径能表示的种类。

我们可以先质因子拆解一些权值10 ^ 10 ^ 100 ,我们发现他是2和5的10 ^ 100的倍数。

然后我们1强连通缩点之后,我们发现只有1所在的强连通块是有用的。现在的问题是怎么考虑回路这个问题?

我们发现一个惯用的思考方式是简单环的合并,在这里,这个题的思考方向也应倾向于简单环。

我们考虑简单环在这里如何构造,怎么处理两个相邻的简单环?

我们把两个简单环的环长分别设置为s1 , s2 。

我们思考两个简单环能表示的数,一个简单环能表示的数为s1 * x , s2 * y , 两个简单环能表示的数就是gcd(s1 , s2) * z 。

在这里我们就可以发现一些性质,即我们求若干个简单环合并后表示数,那我们这道题就显而易见的是求所有简单环的环长的gcd。

然后我们看看gcd 能否被10 ^10 ^ 100整除,由于之前质因子分解为2,5的若干次倍数,因此我们只需要看看gcd是不是质因子分解的质因子只为2,5即可。

例题2codeforces.com/contest/151…

题意:给你n,m的无向带权图,给你q次询问,问是否有从点x开始,点x结束的回路的值 + s能mod 模数t为0?

这道题也是类似的思路,不过这道题思考的东西更多,首先这是无向图,然后构造的东西也很多。

思考方向还是一定要紧靠强连通缩点+简单环。

考虑强连通缩点。

结论1,相同强连通块的任意两个点等价,我们把强连通块"拆解"成若干个简单环,然后简单环加上与否只需要让简单环是否走t * k次即可,因为模t为0 , 我们可以通过该简单环走到任何在简单环上的点且代价为0,所以强连通块的任意两个点等价。

接下来的套路和上述类似,求简单环环长的gcd ——g即可,查询是查看-s 是否是gcd(g, t)的倍数即可。

例题3

某ccpc-final题,or 洛谷题,不记得出处了。

题意 是类似于给你一个无向图求从1开始,1结束的回路的边权异或和是否为x ?

思考方式也是类似,我们考虑简单环的合并,两个相邻简单环怎么合并,我们发现两个简单环都跑一遍的

形式是大环的边权异或和,由于两个简单环的交的边集跑了两遍,所以异或完为0,如果某个简单环不加进去,我们可以让简单环跑两遍即可,然后就构造出来和例题2同等的情况,直接求简单环的线性基即可。

例题4

codeforces.com/contest/183…

这是一道div1 的 D题,在会了前面几道题的基础上,这道题的思考难度应该不会太高,考虑gcd的性质,然后我们可以发现每个点对应的状态固定(即求dfs树的深度),然后分类讨论即可。

dp的另类优化 or 均摊

例题1 : codeforces.com/gym/104385/…

这是江西省赛H题,可以用分治fft做法,但是也可以用dp的优化去过。

这道题其实是有cf原题的,但是记忆不清我也回忆不起来了,不过长途小朋友给了我一个比较好看的题面。

oj.hnist-acm.com/contest/552…

这个题类似于给你若干个物品,物品的重量和为n,求物品能凑出重量x的方案数。

考虑根号分治,我们可以发现种类数最多不超过sqrt(n)个,考虑最坏情况1 + 2 + 3 + .... == n ,我们根据这个定理能够缩小背种类,进一步我们可以发现这是一道分组背包板题,然后可以考虑二进制优化去优化背包,因此可以把这种形式的背包做成O(nsqrt(n))的。

图论的好题

例题1

ac.nowcoder.com/acm/contest…

一道贪心+图论的题目

码量考验 : 低

这道题是一道人类智慧 , 脑电波题,放在这里只是想提供一种解题思路or 方法。

思路很简单,在这里不加叙述。

例题 2

树的好题 类似于优雅的暴力

码量考验 : 低

codeforces.com/contest/179…

能否想到根号分治但是也可以有一种极为复杂的树链剖分做法,但是这种暴力思路非常优美,建议反复掌握。

反悔贪心

例题 : codeforces.com/contest/123…

反悔贪心的主要思想是贪心,和普通的贪心一样,优先考虑维护价值低的,我们可以以这样的思路去考虑,我们可以考虑维护当前能用的最大集合(即装满),然后到消耗的时候,我们一一全部拿出来,然后再装满的一种思路去做。

简单来说就是维护可用集(最优的可用集)。

神仙题 树

给定一棵树,然后若干个点,问你这些点联通所需的最少的边数。

一个结论,我们先对点按照dfs序排序,形成序列p1 , p2 , p3 , p4

然后答案是(1/2)(dis(p1,p2),dis(p2,p3),....)。证明显然。

例题

codeforces.com/problemset/…

哈希技巧

一种是我们最常见的类似于字符串哈希的方法,这样的哈希方式一般强制保持元素间的排列关系。

一种是异或哈希,异或哈希一般指强调含有的元素种类,不强调排列关系,同时异或的性质也会考查,异或哈希一般伴随着随机化,即mt19937_64,如果不用这个随机化赋值,冲突的概率会很大。

例题1

mirror.codeforces.com/contest/141…

例题2

未来我会出在牛客练习赛的一道题,后续发链接吧!

折半搜索学到的两个物品之间的关系转化

不只是适用于折半搜索,这里更着重于两个物品或者两个元素之间的转化

例题1mirror.codeforces.com/contest/125…

这道题是折半搜索的一道题,但是这道题我们可以学到一些经典思路。如两个关系我们保持di + ci = di-1 + ci-1时,我们可以转化为维护一个物品的性质即di-di-1 = ci - ci-1的方式去维护。

例题2ac.nowcoder.com/acm/contest…

这道题着重于怎么把两个数组间的关系变成一个数组内的内部关系求解问题,其实和上述异曲同工,这种思考方式非常常见而且重要。

例题3mirror.codeforces.com/contest/143…

这道题可能说是非常经典的一道题了,这道题我是例题2引申过来的一道题目,这道题经典在于贪心,同时这还撞了2022四川省赛的A题,如果不了解的话,就把他当成典题去补。

例题4ac.nowcoder.com/acm/contest…

四川省赛A

把题全补了可能对这个思想有新的认知,这里只是抛砖引玉,还是希望能学到一些有用的类似两个物品间的关系转化为物内关系。

鸽巢定理

最经典的定理,也是考察很冷门的定理。

考察少而且隐蔽导致这个思想学习效果比较差,但是例题极多,下面会给出几道比较常见的鸽巢题目。

例题1 codeforces.com/contest/117…

一道很有趣而且不难的鸽巢,如果题目不读对,发现不了只包含三个字母的话,那就可能想不到了,如果发现三个字母之后,我们可以拿出最左边两个字母和最右边两个字母,根据鸽巢定理一定会有相同的,不了解的话可以自行了解。

例题 2 ac.nowcoder.com/acm/contest…

例题3 ac.nowcoder.com/acm/contest…

upd 2023/6/24 又刷到一个很好的鸽巢题目!

例题4 codeforces.com/problemset/…

网络流建边技巧

如何表示某条边or某个元素出现cnt次的代价是cnt^2呢。建边技巧:最小费用最大流,我们可以建若干条边,然后是1 , 3 , 5 , 7,....,2n-1,为什么呢,因为最小费用最大流可以优先走代价最小的边,然后我们走的顺序就是从小到大,求和后发现是个n^2,因为n^2-(n-1)^2是2n-1。

例题1 codeforces.com/contest/118…

例题2 codeforces.com/problemset/…

sg函数的深入理解

源于对自己知识的查缺补漏,如果有若干个独立的状态,我们就异或起来,其实得到的是整体的sg函数,根据这点,我们可以很容易地做出以下题目,即求链的sg函数的值。

例题 codeforces.com/contest/182…