一些技巧和套路

套路

  • 碰到一些两两之间的限制条件,可以考虑建图,很可能就是把一些约束条件转化成边,或者是跑网络流。 网络流建模好题1
  • 如果碰到 转移状态很少 或者 情况可数 的题,可以试试看暴力打表或者手推,有概率能出来一些转移矩阵或者规律。
  • 正着不行可以试试反的。比如从终点倒推。或是从起点出发情况很多,但是到终点的情况有限。
  • 有时候要考虑能不能记忆化或者预处理。并不止搜索。比如你走到某个点之后后面的情况是可以预处理的,这种。
  • 有限区间内出现个数这种有时候可以转化成线段覆盖的模型。for example
  • 有状态但是不好推的时候可以考虑转化成状态转移图。比如
  • 觉得很难处理?考虑一些特殊性质。例子
  • 碰到什么“左右括号”“ \(01\)”“前/后缀中 \(A\) 不少于 \(B\) ”这种东西,可以考虑看成 \(01\) 然后做一些结论或者转化成折线。大选
  • 一种奇怪的题意转化:01 数组,选择两个相邻的数并删除,在这个位置加入 x&y 或者 x|y ,可以转化为选择两个相邻数并删除一个 BitOperation

图论

区间向区间连边,\((x+C,y+C)(1\leq C\leq num)\) ,考虑把 \(C\) 二进制拆分,然后维护 \(\log\) 个并查集,如果第 \(i\) 位是 1 那么就把第 \(i\) 个并查集里面的 \(x,y\) 合并。

如果是点向区间连边就是线段树优化建图。


对于一些需要枚举连边的题目,考虑从度数最小的点开始做能得到根号级别的优良复杂度。example


二分图匹配的一个或许有用的定理:ARC106E

Hall 定理(霍尔定理):

设二部图 \(G\) 中的两部分顶点集合分别为 \(X,Y\) (假设有 \(|X|\leq |Y|\) ) ,有完备匹配的充要条件是:

\(X\) 中任意 \(k\) 个点的点集与 \(Y\) 中至少 \(k\) 个点相邻。

推论:

\(N(W)\)\(W\) 的所有邻居,那么二分图最大匹配数是 \(|X|-\max\{|W|-|N(W)|\}\) ,其中 \(W\)\(X\) 的子集。


平面图最大流转最短路(对偶图):狼抓兔子


竞赛图的哈密顿路径应用:CF1514E

(题意:通过 \(O(n)\) 次询问获得一张竞赛图的点对连通状况。查询方式是获得一个点到一个点集的边中是否有出边)

解法:先类似归并排序的方式求出哈密顿路径,然后从后往前查询是否能够回溯,不能就不连通。

详解

找路径:考虑归并。比如找 \([l,r]\) 这些点的哈密顿路径,可以分为 \([l, mid]\)\([mid+1,r]\) 求解。\([l,mid]\) 的哈密顿路径的起点是 \(u\)\([mid+1,r]\) 的是 \(v\) ,进行查询,如果是 \(u \to v\) ,那么就把 \(u\) 放在 \([l,r]\) 的哈密顿路径的第一个,否则把 \(v\) 放在第一个。

查询的时候从后往前枚举,维护一个指针 \(pos\) 表示 \(i\sim n\) 通过往前的边能够向前走到哪里(指 \(pos+1\sim i-1\) 都能走到)。如果 \(pos=i\) 了那么就把 \((1,i)\to(i+1,n)\) 的所有连通性都置为 \(0\) 即可。

相关结论:

  • 对于一个竞赛图,一定有哈密顿通路
  • 对于一个强连通竞赛图,一定有哈密顿回路
  • 竞赛图缩点后肯定是一条链

网络流建模

  • 拆点,按时间、进点出点……
  • 最小割:最大权闭合子图、最大权独立集
  • 可以参考这篇

数据结构

如果并查集直接合并会把两边信息混淆的话,可以考虑建虚点维护

数论

固定一端的序列 gcd 会有 \(\leq \log n\) 个连续段。gcd

字符串

unsigned long long 的 hash技巧

ull nxt_rnd(ull a){a^=a<<15;a^=a>>17;a^=a<<19;return a^1923510;}

scanf("%[^\n]", str) 正则用法,读到回车;%*s 可以空读字符串不存.


长度为 \(n\) 的字符串如果有长度为 \(x\) 的 border ,那么必然有长度为 \(n-x\) 的循环节(不一定完整)神仙的游戏 相关

位运算

有些状压直接转移复杂度太大的,可以考虑高八位和低八位分开算的奇妙trick。(CSP-S 2020初赛)

xza:这个非常常用,大家要掌握


可以试试按位算 or_and

多项式计数&生成函数

  • 恰好 的题能够通过设一个 恰好 和一个 正好 然后反演得到。
  • 普通复杂度太大可以试试转化成下降幂的形式。
  • 碰到 \(siz(c)=siz(a)+siz(b)\) 的题目,可以试试笛卡尔积

\[\ln(1-x)=-\sum_{i=1} \dfrac{x^i}{i} \]

计算几何

结论:对于平面上两点 \(A,B\) 和一个圆 \(O\),直线 \(AB\) 与圆有交,当且仅当 \(A\) 的两切点连线和 \(B\) 的切点连线不相交。CF1446F


结论:设有同圆的两弦 \(A_1A_2,B_1B_2\) ,四个端点极角为 \(\alpha_1,\alpha_2,\beta_1,\beta_2\) ,两弦相交当且仅当区间 \([\alpha_1,\alpha_2]\)\([\beta_1,\beta_2]\) 相交。(出处同上)

卡常

  • 把判断 -1 换成 ~x 能快到飞起……

从兔队的博客里看到的加法取模:

b[i] -= Mod - x, b[i] += b[i] >> 31 & Mod;

大幅度空间优化其实是对时间的另类优化。

据说 memset 是比 fillfor 要快的。


fread 搞的 getchar ,在 歌唱王国 中一下子松了 32ms ……

const int L=1<<20;
char buf[L],*p1,*p2;
#define getchar() (p1==p2?(p2=buf+fread(p1=buf,1,L,stdin),p1==p2?EOF:*p1++):*p1++)

其他

快速根据日期算星期的公式(当然是要真实世界中的年月对应的)(格里高历之前的正确性不明)

ll CalcWeekDay( ll year,ll month,ll date )
{
    if ( month==1ll || month==2ll ) month+=12,year--;
    ll tmp=(date+month*2ll+(month+1)*3ll/5+year+year/4ll-year/100ll+year/400ll)%7ll;
    return (ll)tmp+1;
}
posted @ 2020-11-23 18:02  MontesquieuE  阅读(119)  评论(0编辑  收藏  举报