《算法竞赛进阶指南》0x01
0x00 基本算法
0x01 位运算
算数位运算
与 或 非 (取反) 异或(同为0,异为1)
and,& or,| not,~ xor
补码(-x=~x+1)
32位有符号整数int:以最高位为符号位,0表示非负数,1表示负数;
目的:用加法来实现减法;
等价:一个数与其补码做加减法运算等价于在32位补码下做最高位不进位的二进制加减法运算;
初始化:
int a[maxn];
memset(a,0x3f,sizeof(a));
是将0x3f填充到数组a的每个字节上,一个int有四个字节,所以每个int被赋值为0x3f 3f 3f 3f;
而0x3f3f3f3f是满足以下两个条件的最大整数:
- 整数的两倍不超过int的边界0x7f ff ff ff;
- 每8位(每个字节)都是相同的;
位移运算
左移(=*2)
11——>110 //低位以0填充
1<<n=2^n , n<<1=2n
右移(=/2)
11——>1 //高位以符号填充,低位越界后舍弃
n>>1=[n/2.0]//[]表示向下取整
a^b
求 aa 的 bb 次方对 pp 取模的值。
输入格式
三个整数 a,b,pa,b,p ,在同一行用空格隔开。
输出格式
输出一个整数,表示
a^b mod p的值。数据范围
0≤a,b,p≤1090≤a,b,p≤109
输入样例:
3 2 7输出样例:
2
[√] AC:
//快速幂
#include<iostream>
using namespace std;
int main()
{
int a,b,p;
cin>>a>>b>>p;
int ans=1%p;
while(b)
{
if(b&1) ans=ans*1ll*a%p;
a=a*1ll*a%p;
b=b>>1;
}
cout<<ans<<endl;
return 0;
}
64位整数乘法
求 a 乘 b对 pp取模的值。
输入格式
第一行输入整数a,第二行输入整数b,第三行输入整数p。
输出格式
输出一个整数,表示
a*b mod p的值。数据范围
1≤a,b,p≤10181≤a,b,p≤1018
输入样例:
3 4 5输出样例:
2
[√] AC
//乘法变加法
//a*8=4a+4a
//a*(2^k)=2^k*a
#include<iostream>
using namespace std;
int main()
{
long long a,b,p;
cin>>a>>b>>p;
long long ans=0%p;
while(b)
{
if(b&1) ans=(ans+a)%p;
a=a*2%p;
b=b>>1;
}
cout<<ans<<endl;
return 0;
}
二进制状态压缩
操作 运算
取出整数n在二进制的第k位 (n>>k)&1
取出整数n在二进制的第0~k-1位 n & ((1<<k)-1)
把整数n在二进制的第k位取反 n xor (1<<k)
把整数n在二进制的第k位赋值1 n | (1<<k)
把整数n在二进制的第k位赋值0 n & (~(1<<k))
最短Hamilton路径
给定一张 nn 个点的带权无向图,点从 0~n-1 标号,求起点 0 到终点 n-1 的最短Hamilton路径。 Hamilton路径的定义是从 0 到 n-1 不重不漏地经过每个点恰好一次。
输入格式
第一行输入整数nn。
接下来nn行每行nn个整数,其中第ii行第jj个整数表示点ii到jj的距离(记为a[i,j])。
对于任意的x,y,zx,y,z,数据保证 a[x,x]=0,a[x,y]=a[y,x] 并且 a[x,y]+a[y,z]>=a[x,z]。
输出格式
输出一个整数,表示最短Hamilton路径的长度。
数据范围
1≤n≤201≤n≤20
0≤a[i,j]≤1070≤a[i,j]≤107输入样例:
5 0 2 4 5 1 2 0 6 5 3 4 6 0 8 3 5 5 8 0 5 1 3 3 5 0输出样例:
18
[ ] AC
成对变换
当n为偶数时,n xor 1等于 n+1
当n为奇数时,n xor 1等于 n-1
因此“0和1”,“2和3”,“4和5”……关于xor 1形成“成对变换”。
用处:对于图论的邻接表可以用成对变换来存储成对的正向边和反向边。
lowbit运算
lowbit(n)表示n最低位的1及其后边所有的0
lowbit(111001000)=1000
lowbit(n) = n&(~n+1) = n&(-n)

浙公网安备 33010602011771号