tricks
- 模数不为质数,要除一个数,保证除出来时整数,但是被除数太大了必须中途取模,这时可以将 \(mod\) 乘以除数,边乘被除数边取模,最后答案再除掉除数(常用于组合数的运算)。
假设原本的模数为 \(m\), 要求 \(\dfrac{a}{b} \mod m\), 设 \(a = k \times b \cdot m + r, \dfrac{a}{b} \equiv ans \pmod m, \dfrac{a}{b} = ans + qm, (k, q \in \mathbb{N^*}))\)
可以得到 $$\large{a = k \times b \cdot m + r = (ans + qm) \cdot b}$$
所以是正确的。
- 考虑一个 dp: \(\large{dp_{i,k}=dp_{i-1,k \oplus a_{i}}} (\sum a_i \le m)\), 类似这样的方程如果直接做第二维是值域, 复杂度是 \(O(nm)\) 的.
如果我们考虑将 \(a\) 升序排序, 那么令 \(up_x\) 为 \(2^{\lceil\log(x)\rceil} - 1\), 则 \(up_x < 2 \times x\), 然后做 dp 的时候,前 \(i\) 个数的异或和肯定 \(\le up_{a_i}\), 故第二维只要枚举到 \(up_{a_i}\), 那么时间复杂度就降到了 \(O(n+\sum up_{a_i})=O(n+m)\), 空间复杂度是 \(O(\max up_{a_i})\), 有类似性质的,如 or, and 都可以用这个方法
-
解 \(axy+bx+cy=0\) 的整数解: \(a^2xy+abx+acy+bc=bc \Rightarrow (ax+b)(ay+c)=bc\), 然后枚举 \(bc\) 因数即可。
-
若 \(d | a, d | b\), 那么如果 \(b < 2a\), 则 \(\gcd(a, b) = d\)
-
对于最小生成树,其实不管什么算法,都有很多边的尝试是完全多余的,可以考虑只用有用的边,比如 https://www.luogu.com.cn/problem/P2076
-
经典结论:如果 \(\forall i \in [0, n), i \rightarrow (i + x) \mod n\) 连边, 则会有 \(\gcd(x, n)\) 个等大的连通块
证明:考虑 \(p=0\), 每次 \(+x, \mod n\), 不断跳直到重新为 \(0\), 加的 \(x\) 总和就是 \(\mathrm{lcm(n, x)}\), 有 \(\dfrac{\mathrm{lcm(n,x)}}{x}\) 个点连在一起, \(p\) 等于其它同理,所以共有 \(\dfrac{n}{\dfrac{\mathrm{lcm(n,x)}}{x}} = \gcd(n, x)\) 个连通块。 -
写 gcd 的时候可以先预处理 1000 以内的 gcd,然后大的很快可以辗转相除下来,常数可以小。
-
P7322 「PMOI-4」排列变换 这题不考虑算重非常简单,去重的工作可以容斥,而这个容斥,可以注意到一个非常重要的东西:如果有多个地方,只要考虑第一个,并且第二个成立的区间肯定是接着第一个的,总的符合的也是一个区间,这样就可以直接考虑推柿子,求出重复(即如果 \(i \in [l, l + k - 1]\) 且 \(\max = i\), 那么减去 \(i \in [l + 1, l + k] \land \max = i\) 的情况,这里由于是全排列可以直接算概率。
-
一些可能要可持久化的题,可能可以按时间戳建树,然后跳时间就是连边,离线下来处理。比如可持久化并查集的板子,这样做可以只用可撤销并查集。
-
https://qoj.ac/contest/1259/problem/6631 遇到这种题,发现样例的第二个答案只有 0/1/2, 此时一定要打个表看看是否答案恒 \(\le 2\), 然后想办法构造,构造不了也应该硬猜一下,而且这题可以构造。
-
https://www.cnblogs.com/zhyh/p/15802449.html
有时尺取法删除不好做,比如 \(\gcd\) 和 \(\max\), 这时可以考虑开两个栈维护队列,维护当前区间的 \(l, mid, r\), 记一个 \(res_l, res_r\), 分别表示 \([l, mid], [mid + 1, r]\) 的值,移动 \(r\), 改变 \(l\) 最后统计答案。 -
https://www.luogu.com.cn/problem/P11860
这个题由于点只有一个中转的作用,可以把边看成点,两个"点"之间的权值就是原本这两条边的权值之差,前提是两边有交点,然后可以将边权排序处理,加个超级源点和汇点,就可以跑最短路了。 -
https://www.luogu.com.cn/problem/CF1305G
这个题的特点是:一个点的贡献是 \(out_i \times a_i\), \(out\) 为出度。对于这样的贡献,可以把 \((i,j)\) 边权(无向边)转化为 \(a_i+a_j\), 答案为最大生成树权值减去 \(\sum a_i\), 这是因为入度为 \(1\),所以看成无向图后贡献为 \(\sum (d_i-1) \times a_i\), 推广一下:如果题目贡献和点的度数有关,可以把每条边都加上要贡献的东西,最后减一下不该加的。 -
求自然数幂和一般用插值或者伯努利数解决,但是我不会(,下面是一种另外的递推求解方式:
记 \(\large{S_k(n)=\sum\limits_{i=0}^n i^k}\)
扰动一下,得
整理得:
递推时间复杂度 \(O(n^2)\), 也侧面证明了 \(S_k(n)\) 是一个关于 \(n\) 的 \(k+1\) 次多项式
-
插入直线的李超树是 \(\mathcal{O}(\log n)\) 的,链的并查集是均摊 \(\mathcal{O}(1)\) 的。
-
dp 如果某一维过大但是值域很小,可以尝试交换值域和这一维状态。
-
基于值域的 01 背包可行性(\(n\) 个 \([1, V]\) 的数 \(a_1, a_2, \cdots, a_n\) 凑出 \(S\))做法:正常需要 \(\mathcal{O}(nS) = \mathcal{O}(n^2V)\), bitset 可以除一个 \(\omega\), 然而下面的方法可以做到 \(\mathcal{O}(nV)\).
首先找到最大的 \(pos\) 使得 \(\sum\limits_{i=1}^{pos} a_i \le S\) 如果 \(pos = n\) 直接判断是否取等,否则将序列分为 \(i < pos\) 和 \(i > pos\) 两部分。最终的解一定是从前面丢掉一些后面加上一些。
令 \(sum\) 为当前选取的数的和,初始为 \(\sum\limits_{i=1}^{pos} a_i\), 一次操作如果 \(sum \le S\) 就加入后面的数,否则删掉前面的数,这样会使 \(sum\) 始终在 \((S - V, S + V]\) 中,并且如果有解肯定能构造,并且不会出现丢完/选完的情况(感性理解即可)。
然后从 \(pos\) 开始操作,\(f_{l, r, w}\) 表示前面考虑到了 \(r\) 后面考虑到了 \(l\),能否构造出 \(w\), \(w\) 是 \(\mathcal{O}(V)\) 的,初始状态为 \(f_{pos + 1, pos, sum} = 1\),转移只要枚举上一步的操作即可。时间复杂度 \(\mathcal{O}(n^2V)\)
考虑优化,设 \(g_{r, w}\) 表示最大的 \(l\) 使得 \(f_{l, r, w} = 1\)(显然 \(f_{x, r, w}\) 关于 \(x\) 不增),如果没有记为 \(0\), 转移同理,具体如下:
发现第三个转移是瓶颈。注意到 \(g_{x, w}\) 关于 \(x\) 不减,所以当 \(l < g_{r - 1, w}\) 时已经在 \(r - 1\) 时被转移过了(\(g_{r - 1, w - a_l} \leftarrow l, g_{r, w-a_l} \leftarrow g_{r-1, w-a_l}\) ),只要转移 \(l \ge g_{r - 1, w}\) 即可,时间复杂度 \(\mathcal{O}(V\sum g_{r, w} - g_{r - 1, w}) = \mathcal{O}(nV)\)
-
dijkstra 的复杂度严格上来说不是 \(\mathcal{O}(|E| \log |V|)\) 的,因为这里 \(|E|\) 指的是松弛次数,不是边数,有时候可以优化,详见 https://www.luogu.com.cn/article/cq91ow5i
-
From 冷却心:取模题 ull 一般快于 ll, 不减成负数适合用。
-
乘法优秀取模方法:ll mod2 = mod * mod 之后的乘法如果 >= mod2 减 mod2,最后再 % mod
-
标记永久化:如果一个标记很难 pushdown 就永久化了,比如这题,http://111.229.45.229:8081/p/P1045 ,单调队列维护标记,查询的话在把左右儿子的合并之后和自己的标记合并即可。
-
deque 开 1e6 个会 MLE 怎么办??????vector 又被卡常了咋办?????只需要开一个 basic_queue 数组,里面有足够的空间,然后每个需要的 queue 就以指针的形式开起来,只要保证使用的 basic_queue 的区间不交即可。
-
区间 \([l, r]\) 存在 \(n\) 的倍数的充要条件是 \(\lfloor \dfrac{n}{l-1} \rfloor < \lfloor \dfrac{n}{r} \rfloor\)
-
高斯消元卡常小技巧:使用指针存数组,这样 swap 两个数组就是 \(\mathcal{O}(1)\) 的,常数--
待填坑:

浙公网安备 33010602011771号