- 在加倍数据(比如把一个数组复制两倍,或者题目给了n,实际有2n数据)时,注意数组大小有没有开对,即使是tle也可能是数组开小了。
- 数据范围给的边界数据都可以拿来测一下。
- 看看有没有地方爆了int
- 逆序对是可以局部求解的,可以分开考虑两两之间的贡献。
- 数论分块:在[l,n/(n/l)]内的i,n/i的值都相等,并且n%i是等差数列,公差为(n/l)。
- 一些离散数据相关的题里,在清空数据或用离散的值统计答案时,注意有没有新的值产生。
如https://codeforces.com/contest/1471/problem/D这题里,1可能是原来没有,而过程中产生的。
- 找中位数可以用二分,二分一个w,大于等于w的记为1,其余记为-1,只要区间和大于等于0,就是满足的。
因为中位数一定是原本的数,所以离散化后中位数只可能取1---n。
树状数组上倍增找第k个1要先找第k个1左边位置,然后加1.
int BS(int k)
{
k--;
int p=0;
for(int i=20;i>=0;i--)
if((1<<i)+p<=N&&sum[(1<<i)+p]<=k)
k-=sum[(1<<i)+p],p+=(1<<i);
return p+1;
}
- 历史版本(可持久化数据结构)有离线的一个思路:把每个版本看成节点,版本迁移看成边,然后用数据结构维护遍历和回溯的过程。
- multiset和set的iterator可以用++,- -来移动。( 有时候可以用来代替平衡树)
- double被卡精度时可以开long double(用 %Lf 读入)
- 边权转成点权:可以用一个点把边分成两段,然后这个点就代表了这条边。
- 能合并的东西(如求和,最大值,线性基等)可以考虑用倍增优化(预处理出 i 往前 2^p这一段的值)
- 求树上一段链的信息,除了类似倍增lca一样,也可以模仿st表的思路,把链划成两段(要找上面一段的起点可以类似倍增lca往上走),这么做的好处是在合并复杂度较大的时候,可以把一个log的复杂度转移掉。
- 最小割的可行边与必须边。求一组最小割的方案:现在原图跑最大流,然后把满流边边权改为1,其余改为无穷,再跑一次最大流,这时被割的边就是一组方案。
- 枚举阶乘方案时可以用next_permutation
next_permutation(vec.begin(),vec.end());//得到下一个排列。
- 网格图在相邻格子之间任意连边得到得是一个二分图,无奇环。在网格图上的构造,或者从网格图上抽象出来建的图里经常用到。
- 对于一些问题边界的估计,常量不能忽略,最好写个简单的程序来计算边界。
- 一道题卡20分钟就可以换了。看过题人数,不要作死上鬼畜做法。
- 解线性同余方程
p = a[1]*x[1]+w[1]
p = a[2]*x[2]+w[2]
换成a[1]*x[1]-a[2]*x[2]=w[2]-w[1]
用exgcd做
- exgcd 解 ax+by=c得到的结果(x[0],y[0])是方程ax+by=gcd(a,b)的解,换算成原方程的解是(x[0]c/gcd(a,b),y[0]c/gcd(a,b))
- f[i]g[n-i]的求和直接卷积。f[i]g[j+i]的求和可以令G[n-i]=g[i]后,转换成f[i]G[(n-j)-i]后卷积求和。
- 在模p意义下,存在一个i:[1,p-1]到j:[0,p-2]的一一映射关系,(设g为p的原根)映射关系是g^j=i(mod p) .用这个映射可以把 H[i]G[j] (i*j=C)变换成卷积的形式。