算法模板
a.位运算
1.快速幂
ll qmi(int m, int k, int p)
{
ll res = 1 % p, t = m;
while (k)
{
if (k&1) res = res * t % p;
t = t * t % p;
k >>= 1;
}
return res;
}
b.前缀和与差分
1.一维前缀和
a数组:1 2 3 4 5 6
b数组:1 3 6 10 15 21
\(b[i] = a[i] + b[i - 1] (下标从1开始)\)
求1,2的和,就可以转换为\(b[2] - b[1 - 1]\),也就是求\(l-r\),为\(b[r] - b[l - 1]\);
2.二维前缀和
通过一维前缀和我们自然也可以推出二维前缀和
\(s[x2][y2] - s[x2][y1 - 1] - s[x1 - 1][y2] + s[x1 - 1][y1 - 1]\)为从(x1,y1)到(x2,y2)二维数组内的元素之和
例如
图片s(x2,y2)为从(0,0)到此的总和,s(x1,y1)为从(0,0)到此的和。我们在如果要算(x1,y1)到(x2,y2)的之间元素的总和,我们需要把s(x2,y2)减去s(x2,y1)以及s(x1,y2)
然后还要加上s(x1,y1),因为该区域被减了二次。
所以可以得出\(s[x2][y2] - s[x2][y1 - 1] - s[x1 - 1][y2] + s[x1 - 1][y1 - 1]\)公式,
\(s[x2][y1 - 1]\)可以类比一维的前缀和,我们是减去下标前面的下标,之后也是相类似。
3.一维差分
1 2 3 4 5 6
1 1 1 1 1 1
差分处理:b[i] = a[i] - a[i - 1]
场景:
我们将下标1到下标3的数每个数加上一
使用朴素做法,那么我们就要变量区域的每一个值加上一,\(0(n)\)的时间复杂度。
使用差分数组,\(b[3 + 1] --,b[1]++\),只需要0(1)的时间复杂度。
还原数组:b[i] += b[i - 1]
4.二维差分
使用上面二维前缀和的例子
将(x1,y1)到(x2,y2)区域的数组同时减或者加。
\[s[x2 + 1][y2 + 1] += c\newline
s[x2 + 1][y1] -= c\newline
s[x1][y2 + 1] -= c\newline
s[x1][y1] += c
\]
类似一维差分,是数组的下一个下标进行。