按位与(Bitwise AND)是一种二进制运算,它逐位对两个数的二进制表示进行运算。对于每一位,只有两个相应的位都为1时,结果位才为1;否则,结果位为0。如:十进制9 & 5转化为二进制:(1001)&(0101)=0001。
>>
<<
-
左移(
<<
):将一个无符号整数左移n位,相当于将该数乘以2n。这是因为每向左移动一位,就相当于在数的末尾添加了一个0(在二进制表示中),这等价于乘以2。 -
右移(
>>
):将一个无符号整数右移n位,相当于将该数除以2n并向下取整。这是因为每向右移动一位,就相当于去掉了数末尾的一个0(或更准确地说,是将数除以2并丢弃余数),这等价于除以2.
无符号代表没有溢出,如果有符号为int,则可能会爆int
举个例子:
关于右移(Right Shift)和左移(Left Shift)操作的具体例子,我们将使用8位二进制数(仅为了简化说明,实际中整数可能使用更多位)来展示这些操作。
左移(Left Shift)例子
假设我们有一个无符号的8位二进制数 00001010
,它等于十进制的 10
。现在,我们将其向左移动2位。
原始数(二进制):00001010
左移2位后的结果:
- 将原始数的二进制表示向左移动2位。
- 左侧超出的位(在这个例子中是最高位左边的所有位)将被丢弃。
- 在右侧新增的2位上,全部填充0。
因此,左移2位后的结果是:00101000
,这等于十进制的 40
。
右移(Right Shift)例子
现在,我们考虑一个有符号的8位二进制数 -00001010
(注意:在实际的二进制补码表示中,负数不会以这种方式直接显示,但这里为了说明右移操作,我们暂时这样表示)。在补码表示中,10001010
表示 -10
(假设最高位是符号位,1表示负数)。现在,我们将其向右移动2位。
但是,由于直接以这种方式表示负数可能会导致混淆,我们将直接使用补码表示的 -10
来进行说明。
原始数(补码,二进制):11110110
(这是-10在8位二进制补码表示中的值,注意这里的最高位是符号位)
右移2位(算术右移)后的结果(大多数编程语言对于有符号整数使用算术右移):
- 将原始数的二进制表示向右移动2位。
- 右侧超出的位(在这个例子中是最低位右边的所有位)将被丢弃。
- 在左侧新增的2位上,用符号位的值(1,因为这是一个负数)来填充。
因此,算术右移2位后的结果是:11111011
,这等于十进制的 -3
(在8位补码表示中)。
注意:上面的右移结果-3
是基于算术右移的假设。如果使用的是逻辑右移(左侧新增的位全部填充0),则结果将是不同的正数(但在这个例子中,由于原始数是负数,逻辑右移通常不适用于表示相同的负数结果)。然而,在大多数编程语言中,对于有符号整数,右移操作默认为算术右移。
快速幂:快速的求出一个幂mod一个数的值
假设
代码:
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long LL;
int n;
int quick_mi(int a,int b,int p)
{
LL res=1%p;
while(b)
{
//将b转化为2进制时按位与1,当b=0时,结束快速幂
if(b&1) res=res*a%p;
//舍弃b在二进制下的最后一位
b = b >> 1;
//上一个a^2%p
a=(LL)a*a%p;
}
return res;
}
int main()
{
scanf("%d",&n);
while(n--)
{
int a,b,c;
scanf("%d%d%d",&a,&b,&c);
printf("%d\n",quick_mi(a,b,c));
}
return 0;
}
题目即是要求:b^(m-2)。
证明:
由若整数 b,m 互质,并且对于任意的整数 a,如果满足 b|a,则存在一个整数 x,使得 a/b≡a*x(mod m),则称 x 为 b 的模 m 乘法逆元,记为 b^(-1)(mod m)。等式两端约去a,得1/b≡b^(-1)(mod m)➡等式两端同时乘以b,得1≡b^(-1)*b(mod m)。也就是b*b^(-1)≡1(mod m),因为b与m互质,且m为质数,由费马小定理可得b^(m-1)≡1(mod m),也就是b*b^(m-1)≡1(mod m),所以b^(m−2) 即为 b的乘法逆元
代码:
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long LL;
int n;
int quick_mi(int a,int b,int p)
{
LL res=1;
while(b)
{
if(b&1) res=res*a%p;
a=(LL)a*a%p;
b>>=1;
}
return res;
}
int main()
{
scanf("%d",&n);
while(n--)
{
int a,b;
scanf("%d%d",&a,&b);
int t=quick_mi(a,b-2,b);
//特判一下,只有当a与b互质时才成立
if(a%b) printf("%d\n",t);
else printf("impossible\n");
}
return 0;
}
费马小定理: