快速幂和位运算
一.位运算
1.~
:取反
原:10010
~: 01101
注:相反数=该数 取反+1
有符号整数的最小负数无法求出相反数
2.|
:或
a: 0010
b: 1010
a|b:1010 (有1就为1)
3.&
:与
a: 1010
b: 0011
a&b:0010 (都是1才为1)
例子:判断一个数是不是2的幂
bool f(int n) {
if (n <= 0) return false;
return (n & (n - 1)) == 0;
}
int main() {
int num;
cin >> num;
if(f(num)) {
cout << "YES";
} else {
cout << "NO";
}
return 0;
}
4.^
:异或
a: 1010
b: 0110
a^b:1100 (数一样就为0)
1.0^n=n
2.n^n=0
3.a^b^c^d=(a^c)^b^d=……
4.若a^b=c
则a^c=b b^c=a
例题:有a个白球,b个黑球,取出两球,若取出2白或2黑则放入 1白球,若1黑1白则放入一个黑球,求最后所剩球的颜色
联想到^同为1或0的时候得到0即白球相当于0,黑球相当于1
就相当于a个0和b个1异或
则如果b为偶则必定为白反之必定为黑
5.<<
:左移 >>
:右移
a: 0101010
a<<1:1010100
a>>1:0010101
6.如何打印一个数的二进制
1)数组
int a[32];
int main()
{
//打印a的二进制
int num=10;
for(int i=31;i>=0;i--)
{
//printf("%d",a&(1<<i)==0?0:1);
a[i]=num%2;
num/=2;
}
for(int i=0;i<32;i++)
{
cout<<a[i];
}
return 0;
}
2)位操作打印
int y,num;
scanf("%d",&num);
for(int i=31;i>=0;i--)
{
y=(num>>i)%2;
printf("%d",num>0?y:-y);
}
二.快速幂
1.引入
例:求(a^b)%c. a,b,c都是整数且0<a,c<10^9, 0<b<10^18
ll a,b,c;
cin>>a>>b>>c;
ll ans=1;
for(ll i=0;i<b;i++)
{
ans*=a;
}
ans%=c;
cout<<ans;
在计算ans*=a的时候ans可能会超出long long 的范围
算法复杂度:O(b)
2.优化
(a*b)%p=[(a%p)*(b%p)]%p
ll a,b,c;
cin>>a>>b>>c;
ll ans=1;
for(ll i=0;i<b;i++)
{
ans*=a;
ans%=c;
}
cout<<ans;
算法复杂度:O(b) ,并未优化
3.快速幂
例:3^10 = (3^2) ^ 5 = 9 ^ 5
9^5=9 * 9^4=9 * ( 9^2 )^2=9 * 81^2
规律:指数为偶数,底数平方,指数除以2
指数为奇数,乘以底数,再令指数减1
此时复杂度为:log2(10^18)
#define ll long long
ll f(ll a,ll b,ll c)
{
ll ans=1;
a%=c;
while(b)
{
if(b%2==1)
{
ans*=a;
ans%=c;
}
a=(a*a)%c;
b/=2;
}
return ans;
}
int main()
{
ll x,y,z;
cin>>x>>y>>z;
ll ans=f(x,y,z);
cout<<ans;
return 0;
}
4.迭代实现
例:5^13
将13用二进制表示:1101
5^13=5^(2^0)+5^(2^1)+5^(2^2)+5^(2^3)
#define ll long long
ll f(ll a,ll b,ll c)
{
ll ans=1;
while(b>0)
{
if(b&1)
{
ans=(ans*a)%c;
}
a=(a*a)%c;
b>>=1; // b/=2
}
return ans;
}
int main()
{
ll x,y,z;
cin>>x>>y>>z;
ll ans=f(x,y,z);
cout<<ans;
return 0;
}