做题随记

P2822 [NOIP 2016 提高组] 组合数问题

  1. 问一个数是否是 \(k\) 的倍数,事实上就是问这个数 \(mod\ k\) 是否等于 \(0\)
  2. 当出现,一个数列,对于所有的数,满足一个固定条件就计数,并且多组询问时,考虑用前缀和

P4185 [USACO18JAN] MooTube G

  1. 最后无修改且多次询问,考虑离线下来排序后做。
  2. 离线的一种方式是,排序后逐个遍历所有的询问,把当前询问所需要的信息都加入,计算当前答案。
  3. 并查集维护集合的 \(size\) 时,只需要在合并处维护,最后查找该集合根节点 \(i\)\(size_i\) 即可。

P1525 [NOIP 2010 提高组] 关押罪犯

  1. 在一张二分图上,不断执行删边操作,”该图还是二分图“的性质是满足单调性的,即这张图变为非二分图后不可能再变回二分图。
  2. 给出两个点的独立关系(指规定这两个点分属不同集合),可以使用扩展域并查集,令点 \(i+n\) 为点 \(i\)假想敌,合并 \((x,y)\) 时,变为合并 \((x+n,y)\)\((x,y+n)\)。即敌人的敌人是朋友。注意 \(f\) 数组要开两倍空间
  3. 同时也可以简单的只用一个数组 \(enemy_i\) 表示 \(i\) 的一个敌人(一般取第一个即可),每次令 \(x\)\(enemy_y\) 合并,这样使得最后这些点都通过这个 \(eneny_y\) 串联进同一个集合。对于 \((y,enemy_x)\) 做相同操作即可。

P1892 [BalticOI 2003] 团伙

  1. 注意,做扩展域并查集时,习惯的\(1\sim n\) 的节点当根,这样可以避免统计时的错误(比如统计 \(1\sim n\) 的集合数量时,只统计 \(1\sim n\) 中满足 \(f_i=i\) 个数的方法可能导致一些节点的根在 \(n+1\sim 2n\) 的点上而漏情况。

P1196 [NOI2002] 银河英雄传说

  1. 带权并查集上,求同一集内的两点之间的点的数目,应是 \(|d_x-d_y|-1\),注意 \(-1\) 写在绝对值外面。

CF776D The Door Problem

  1. 扩展域并查集判断冲突:如果 \(find_i=find_{i+n}\) 则冲突。

P2290 [HNOI2004] 树的计数

  1. 树的形态计数考虑 \(prufer\)
  2. 树的结点数 \(N\) 与 点度数和 \(sumd\) 的关系:每条边贡献 \(2\) 的度,点比边多 \(1\),故 \(sumd=2N-2\)
  3. 预处理组合数的初始化:\(c_{0,0}=c_{1,0}=c_{1,1}=1,c_{i,0}=1\)

P9619 生成树

  1. \(Trick\) - 均摊边:比如,要求每条边在所有生成树的出现次数,我们已知:生成树的总数量,每个生成树的边条数,于是我们可以算出所有生成树的总边数。因为每条边在生成树中出现的次数相等,所以可以把算出的总数量均摊到每一条边,算出每条边共出现几次。其实就是每个物品单独的信息不好算时,考虑若每个物品等价,则可以先算出总共的,再均摊到每一个
  2. 看到异或时,考虑拆位,对每个二进制位计算贡献。例如,计算所有点对两两异或之和,此时仅当这两个点分别为 \(0,1\) 时才能产生贡献。于是对于每一位,可以分别算对于所有点,该位为 \(0,1\) 的点的个数。那该位的总贡献就是为 \(0\) 的与为 \(1\) 的两两组合的数目,乘上该位的位权。

AT_abc201_e [ABC201E] Xor Distances

  1. 处理树上任意两点间简单路径边权的异或和,定义为 \(dis_{i,j}\):先从根节点开始,令每个点的点权 \(d\)从根节点到该点的路径上,边权的异或和。这样处理之后,因为一个数被异或两次后不变,所以 \(dis_{i,j}=d_i \oplus d_j\)
  2. 表达式 \(1<<x\) 的类型取决于 \(1\) 的类型,所以写 \(1<<60\) 是会溢出的,应当写 \(1ll<<60\)

P2142 高精度减法

  1. 输出结果需要清除前导 \(0\)
  2. 清除前导 \(0\) 时注意不能全部清完,需保留一位,以防输出结果就是 \(0\)
  3. 比较两个字符串的数值是否相等:\(size\) 大的数值更大,若 \(size\) 相等则直接 \(<\) 比较。

P2624 [HNOI2008] 明明的烦恼

  1. 频繁对多个数分解质因数的方法:预处理出范围内每个数的最小质因数,此后对于一个数,每次除去它的最小质因数并统计。
  2. 算组合数的时候,特殊情况下,把要计算(相乘)的每个数转化为它的质因数的乘积,对他们的质因数的次数分别加减,最后再全部乘起来。

CF156D Clues

  1. 有时候特判的时候不一定是直接输出 \(1\),比如此时 \(mod=1\) 就要输出 \(0\),即特判的时候要注意是否还需要再判一次 \(mod\)
  2. 利用化归的思想:把连通块视作一个点,分开考虑每个连通块内的方案数,以及各个点(实际是连通块)之间的方案数(化归到点就可以套用结论),最后再计算。

P5596 【XR-4】题

  1. 推数学式子的题也可能不是 \(\mathcal O(1)\) 能算答案,到最后可能需要枚举。
  2. 有两个未知数时,可以考虑消掉一个,具体地,可以用一个表示另一个,最后在合法区间内枚举其中一个,并判断另一个是否满足条件。常见条件有化成分数后判断是否为整数(即分子为分母倍数)。事实上,枚举的也不一定能够需要是其中一个未知数,也可以先找到一个和这两个未知数有关的式子来枚举(比如 \(y-x\))。
  3. 我们期望,你用分数表示一个变量时,分子和分母分别具有相反的单调性,这样可以在满足特定条件时退出。

P4921 [MtOI2018] 情侣?给我烧了!

  1. 逆元算组合数时,\(inv_i\) 表示 \(i!\) 的逆元。\(fac_i,inv_i\) 都需要计算 \(i=0\) 的情况。\(0!=1\)
  2. 推式子的时候,如果有满足:不能用已有公式表示、步骤间存在一定递推性、步骤中重复出现的式子,考虑用一个数组来表示(比如本题用 \(f_i\) 表示 \(i\) 对情侣在 \(i\) 排座位里,每一对都不坐在同一排的方案数),并寻找数组间邻项的关系,考虑通过递推预处理数组。
  3. 推式子时常常需要对当下这一项新加入的元素分类讨论不同的情况,分别推式子后组合为总答案式。

P11362 [NOIP2024] 遗失的赋值

  1. 先判无解。先判无解。先判无解。别忘了判无解。
  2. 普通快速幂不能处理负指数,会死循环。
  3. 推出递推式子之后,观察式子是否能变成 \(\mathcal O(1)\) 求,可以通过多代几个相邻值的方法,若发现一些式最后被化掉了,使得邻项的形式也和原式类似,考虑能不能表示出通项公式(比如,使得$$f_x=...+f_{x-1} \to f_x=...+f_{x-k}$$然后再令 \(k=x-1\),得到 \(f_x\)\(f_1\) 的关系,再利用边界条件化为与 \(f\) 无关的式子。
  4. 可以考虑分段计算贡献,把原数组拆分成若干个具有相同特征的项(比如该题,拆成两端有限制,中间没限制的最小区间),分别计算每一个相加。此时注意考虑开头和结尾的特殊性。

P2429 制杖题

  1. 算答案的时候,中间有除法,先除完在取模,不能中间先取模再除。
    2.容斥时, \(dfs\) 比二进制枚举复杂度低,有些状态可以提前判超过限制,可以避免后面的冗余条件访问,相当于一种剪枝。
  2. 做容斥,二进制枚举从 \(1\) 开始。

区间整除数

  1. 加入一个新的数,更新这多个数的 \(\text lcm\):$$\text lcm=\text lcm*a_i \div \gcd(\text lcm,a_i)$$
  2. 至少被 \(a\) 的一个数整除,没有保证 \(a\) 为质数(实质是互质),则需要用 \(\text lcm(a\in mask)\) 来求,而不能直接用 \(\prod a\in mask\)。求 \([L,R]\) 间能被当前所选数整除的数的个数:$$\left \lfloor \frac{R}{\text lcm(a\in mask)}\right \rfloor-\left \lfloor \frac{L-1}{\text lcm(a\in mask)}\right \rfloor$$

P5123 [USACO18DEC] Cowpatibility G

  1. 求有多少对完全无交集的集合:一定要直接判断对应的集合在之前出现了多少次,把每一个集合存起来,累加出现次数。存集合可以用一个 \(map<string,int>\),先把全集排序,之后枚举时给每一个所选元素后面加一个空格,最后存入这个字符串。
  2. 不要直接把数字转成 \(char\)因为数字不一定是个位数!可以用 \(to\_string\),当然最好是输入的时候就直接当 \(string\) 来输入。

P5505 [JSOI2011] 分特产

  1. \(n\) 个人中至少 \(i\) 个人不怎么样 = 恰好 \(i\) 个人不怎么样 + 剩下 \(n-i\) 个人无约束。
  2. \(m\) 种东西,每种有 \(a_i\) 个,这样的分配求方案数的问题,可以把 \(m\) 种东西分开处理,每次考虑其中一种的分配方案,最后再相乘。

P5664 [CSP-S 2019] Emiya 家今天的饭

  1. 出现每个数的出现次数都不能超过总的一半的限制时,可以考虑到,最多只会有 \(1\) 个数不合法,因为不可能同时有两个数出现次数超过一半。

P1095 [NOIP 2007 普及组] 守望者的逃离

  1. 注意 \(dp\) 中有些状态可能根本无法到达,只能用存在的状态去更新(尤其是二维 \(dp\) 时)(计数的没关系,那些本来就是 \(0\),但是取最大值之类的话,就有可能被错误的更新(本来这些状态不应该拿出来更新)。

P1077 [NOIP 2012 普及组] 摆花

  1. \(dp\) 习惯写某个状态从哪些旧状态转移来的递推式,而不是某个状态能转移到哪些新状态,这样可以降低复杂度。

P4059 [Code+#1] 找爸爸

  1. 初始时不想要某些状态参与更新,就赋极值。
  2. \(0\) 下标有关的值都要考虑是否需要初始化。

P2602 [ZJOI2010] 数字计数

  1. 通过取一个数的每一位把这个数算出来时,必须从个位开始。
  2. 数位 dp 的 \(dp_i\) 表示的是i位数的每个数出现的次数,每一位应该先加上 00,000,010 这种情况,再全部减去。

P3755 [CQOI2017] 老C的任务

  1. 离散化还是 \(x,y\) 分开写吧,不要揉在一起了,以防出错。
  2. 养成良好的代码习惯,出错时记得要检查是不是有自己写的函数没调用(比如 cmp),自定义的函数最好是用到了再写。

P3387 【模板】缩点

  1. 缩点记录原边时数组要开到 \(m\)
posted @ 2025-11-20 20:54  Sqqqz185  阅读(6)  评论(0)    收藏  举报