一.快速运算
快速幂:二进制位拆分的思想
const ll mod=1000000007;
ll ksm(ll a,ll b){
ll ans=1;
for(;b;b>>=1){
if(b&1) ans=ans*a%mod;
a=a*a%mod;
}
return ans;
}
快速乘:类似快速幂
const ll mod=1000000007;
ll ksm(ll a,ll b){
ll ans=0;
for(;b;b>>=1){
if(b&1) ans=(ans+a)%mod;
a=a*2%mod;
}
return ans;
}
二:位运算
快速swap:
void swap(int x,int y){x^=y,y^=x,x^=y;}
lowbit取位:
#define lowbit(x) x&-x;
*运算符优先级(升序):
加减 移位 比较大小 与 异或 或
三.枚举
枚举的几个要点:
1.规划好要枚举的东西
2.减少不必要的枚举
枚举可以用递归,递推,位运算,循环等方式来实现
四.前缀和
O
(
n
)
O(n)
O(n)预处理,
O
(
1
)
O(1)
O(1)查询区间和
拓展:
1.差分前缀和POJ3263
2.二维前缀和
五.递归
在函数中调用它本身的操作
可以实现一些循环无法实现(或者很难实现)的枚举
例题:POJ2083
六.分治
二分:
单调区间内
O
(
l
o
g
N
)
O(logN)
O(logN)查找某个值的算法
有二分答案,二分查找两种常见形式
二分答案:常见于“最大最小”这类问题,先确定答案范围(上下界)然后二分出答案的预估值,再验证是否合法,然后对上下界作出适当调整POJ2018
二分查找几种形式:
//单调递增序列a中查找>=x的数中最小的一个(即x或x的后继)
while(l<r)
{
int mid=(l+r)/2;
if(a[mid]>=x)
r=mid;
else
l=mid-1;
}
return a[l];
//单调递增序列a中查找<=x的数中最大的一个(即x或x的前驱)
while(l<r)
{
int mid=(l+r+1)/2;
if(a[mid]<=x)
l=mid;
else
r=mid-1;
}
return a[l];
//实数域上的二分
while(l+1e-5<r)
{
double mid=(l+r)/2;
if(calc(mid))
r=mid;
else
l=mid;
}
//实数:二分100次
for(int i=0;i<100;i++)
{
double mid=(l+r)/2;
if(calc(mid))
r=mid;
else
l=mid;
}
拓展:三分
分治:
分而治之,将问题分为多个部,分别求解后合起来统计答案
经典例题:POJ3714
七.排序
1.
O
(
n
2
)
O(n^2)
O(n2)排序:用的很少
2.快速排序:c++选手常用sort实现
3.归并排序:可求逆序对
4.桶排序:计数时常用
离散化:
用map或者数组实现,便于桶排序等算法统计
O
(
n
)
O(n)
O(n)k大数:
排序时,统计左半部分的大于基准值的数个数,然后和k比较并且下一次操作只往左或右边操作
八.倍增
先求解以2的整数次幂为底数的答案,再拼合起来,复杂度logn
应用:女选手 求LCA,ST表
九.贪心
每一步操作都选择最优的情况,是重要的得分算法