位运算
位运算:程序中的所有数在计算机中都是以二进制的形式存储的,位运算是直接对整数在内存中的二进制位进行操作。
1.位与(&)运算
比如6的二进制是110,11的二进制数是1011,那么6&11的结果就是2。运算的时候写成一个竖式的形式,只有同为1的时候才是1,其余都是0。判断是否是奇数还是偶数,就可以用位与运算,当x&1=1的时候说明是奇数,等于0的时候说明是偶数。比如2的二进制数是10,对1进行位与运算,结果为0,2是偶数。又比如3的二进制是11,对1进行位与运算,结果为1,说明3是奇数。处理的速度非常快。
2.位或(|)运算
这个就是只要有一个为1,结果就是1。就是不进位加法运算。如果需要把二进制最末位变成0,就需要对这个数|1之后再减一就行了,实际意义就是把这个数强行变成最接近的偶数。
3.位异或(^)运算
计算方法就是0和1异或0都不变,异或1则取反。两次异或同一个数最后结果不变。
两个交换操作:
a=a+b;
b=a-b;
a=a-b;
或者:
a=a^b;
b=a^b;
a=a^b;
上面两个方法都可以实现交换操作。
4.位取反(~)运算
这个就是把内存中的0和1全部取反,这个用的少点好像。
5.位左移(<<)运算
a<<b就表示把a转化为二进制后左移b位,就是在后面添加b个0。可以理解为,在二进制后面添加一个0,就是将这个数扩大两倍,所以a<<b就是a乘以2的b次方。
比较常用的就是a<<1操作,代表将原来的数乘以2,比单纯的乘以2操作要快很多。
6.位右移(>>)运算
a>>b表示二进制右移b位,就是去掉末尾b位,相当于a除以2的b次方,这里注意,如果是个小数是要取整的。常用的就是>>1代替除以2,比如二分查找,堆的插入操作等。
递归
搜索模板的套路:
先判断是否达到目标状态。
如果达到,判断当前状态是否合法是否计入答案。
未达到,枚举可能的状态,记录本轮选择,进入下一层。
返回后,消除影响。
简单递归实现斐波那契数列:
#include <bits/stdc++.h>
using namespace std;
int arr[101];
int fei(int i)
{
if (i == 1 || i == 2)
return 1;
else
return fei(i - 1) + fei(i - 2);
}
int main()
{
arr[1] = 1;
arr[2] = 1;
for (int i = 1; i < 30;i++)
{
cout << fei(i) << endl;
}
return 0;
}
n元环互质实例:
#include <bits/stdc++.h>
using namespace std;
bool vis[20];
int ans = 0;
bool isprime(int x) {
for (int i = 2; i <= sqrt(x); i++) {
if (x % i == 0)return false;
}
return true;
}
int a[100], n=3;
void dfs(int now) {
if (now == n + 1) {
if (!isprime(a[1] + a[n]))return;
for (int i = 2; i <= n; i++) {
if (!isprime(a[i] + a[i - 1]))return;
}
ans++; return;
}
for (int i = 1; i <= 20; i++) {
if (!vis[i]) {
vis[i] = 1; a[now] = i;
dfs(now + 1);
vis[i] = 0;
}
}
}
int main()
{
dfs(3);
cout << ans;
return 0;
}
二分答案
类似于最大值最小/最小值最大。
最靠近某个值。
最小的能满足条件的代价,通常都可以往二分答案去想。
while (left < right) {
int mid = (left + right) / 2;
if (check(mid))right = mid;
else left = mid + 1;
}
answer = left;