位运算和(矩阵)快速幂
位运算
& 运算
and运算通常用于二进制的取位操作,例如一个数 and 1的结果就是取二进制的最末位。这可以用来判断一个整数的奇偶,二进制的最末位为0表示该数为偶数,最末位为1表示该数为奇数。
or 运算
or运算通常用于二进制特定位上的无条件赋值,例如一个数or 1的结果就是把二进制最末位强行变成1。如果需要把二进制最末位变成0,对这个数or 1之后再减一就可以了,其实际意义就是把这个数强行变成最接近的偶数。
xor运算 ^
异或的符号是^。按位异或运算, 对等长二进制模式按位或二进制数的每一位执行逻辑按位异或操作. 操作的结果是如果某位不同则该位为1, 否则该位为0.
~ 运算
not运算的定义是把内存中的0和1全部取反。使用not运算时要格外小心,你需要注意整数类型有没有符号。如果not的对象是无符号整数(不能表示负数),那么得到的值就是它与该类型上界的差,因为无符号类型的数是用00到$FFFF依次表示的。
shi运算 <<
a shl b就表示把a转为二进制后左移b位(在后面添b个0)。例如100的二进制为1100100,而110010000转成十进制是400,那么100 shl 2 = 400。可以看出,a shl b的值实际上就是a乘以2的b次方,因为在二进制数后添一个0就相当于该数乘以2。
通常认为a shl 1比a * 2更快,因为前者是更底层一些的操作。因此程序中乘以2的操作请尽量用左移一位来代替。
shr 运算 >>
和shl相似,a shr b表示二进制右移b位(去掉末b位),相当于a除以2的b次方(取整)。我们也经常用shr 1来代替div 2,比如二分查找、堆的插入操作等等。想办法用shr代替除法运算可以使程序效率大大提高。最大公约数的二进制算法用除以2操作来代替慢得出奇的mod运算,效率可以提高60%。
优先级
1 | ~ |
---|---|
2 | <<, >> |
3 | & |
4 | ^ |
5. | \ |
6 | &=, ^=, |=, <<= , >>= |
(矩阵)快速幂
矩阵快速幂能减少运算次数,加快运行速度
快速幂基本代码
A-最低位
题目大意:输入一个十进制整数,输入其对应二进制从右向左数的第一个为1的对应的十进制数
例: 输入26,其对应二进制为11010,最小为10,所以输出2;
题解
这道题就是位运算的运用,代码如下:
#include<iostream>
using namespace std;
int main()
{
int a;
while(cin>>a && a != 0)
{
int result = 1;
while(!(a&1))
{
result *= 2;
a >>= 1;
}
cout<<result<<endl;
}
return 0;
}
C-麦哲伦的异或
代码如下
#include<iostream>
using namespace std;
int main()
{
int N;
cin>>N;
while(N--)
{
int n,m,z,l;
long long a[n];
cin>>n>>m>>z>>l;
a[0] = 0;
for(int i = 1;i < n;i++)
a[i] = (a[i-1]*m+z)%l;
long long result = 0;
for(int i = 1;i < n;i++)
result ^= (a[i]+a[i]);
cout<<result<<endl;
}
return 0;
}
这道题要注意最后会生成一个数组,但是我们知道数组的a[i][j] = a[j][i] ,异或之后都为0,只剩下主对角线上的元素。
D-a的b次
代码如下:
#include<iostream>
using namespace std;
long long quickPow(int x,int n);
int main()
{
int x,n;
while(cin>>x>>n && (!x==0&&!n==0))
cout<<quickPow(x,n)<<endl;
return 0;
}
long long quickPow(int x,int n)
{
long long res = 1;
while(n > 0)
{
if((n&1))
res = (res*x) % 1000;
x = (x*x) % 1000;
n >>= 1;
}
return res;
}
这道题就是快速幂的基本运用
E-取模运算
代码如下
#include<iostream>
using namespace std;
struct matrix
{
long long m[4501][2];
};
int mul(long long x,long long n,int m);
int main()
{
int Z;
cin>>Z;
while(Z--)
{
int M,H;
cin>>M>>H;
matrix array;
for(int i = 0;i < H;i++)
for(int j = 0;j < 2;j++)
cin>>array.m[i][j];
int sum = 0;
for(int i = 0;i < H;i++)
sum = (sum + mul(array.m[i][0],array.m[i][1],M))%M;
cout<<sum<<endl;
}
return 0;
}
int mul(long long x,long long n,int m)
{
long long res = 1;
while(n>0)
{
if((n&1))
res = (res * x) % m;
x = x * x % m;
n >>= 1;
}
return res;
}
这道题也是快速幂的运用,但需要注意不仅刚开始定义类型要大,中间产生的变量定义类型也要大,不然也会爆栈;
F-一系列数字
代码如下:
#include<iostream>
using namespace std;
long long equalDifference(long long a,long long b,int k);
long long equalRatio(long long a,long long b,int k);
int main()
{
int N;
cin>>N;
while(N--)
{
long long a,b,c,result;
int k;
cin>>a>>b>>c>>k;
if((b-a)==(c-b))
result = equalDifference(a,b,k);
else
result = equalRatio(a,b,k);
cout<<result<<endl;
}
return 0;
}
long long equalDifference(long long a,long long b,int k)
{
long long res;
res = a + (k-1)*(b-a);
return res%200907;
}
long long equalRatio(long long a,long long b,int k)
{
long long q = b / a;
long long res = 1;
k = k-1;
while(k>0)
{
if((k&1))
res = res*q % 200907;
q = q * q % 200907;
k >>= 1;
}
res = res * a % 200907;
return res;
}
这道题是要知道分为两种数列,等差或者等比,之后分别构造函数就行。也是有快速幂和位运算的应用。
G-Fibonacci
代码如下:
#include<iostream>
using namespace std;
struct matrix
{
long long m[2][2];
};
matrix multiply(matrix a,matrix b);
void mul(long long n);
int main()
{
long long n;
while(cin>>n && n != -1)
{
mul(n);
cout<<endl;
}
return 0;
}
matrix multiply(matrix a,matrix b)
{
matrix c;
for(int i = 0;i < 2;i++)
for(int j = 0;j < 2;j++)
c.m[i][j] = 0;
for(int i = 0;i < 2;i++)
for(int j = 0;j < 2;j++)
for(int k = 0;k < 2;k++)
c.m[i][j] = (c.m[i][j] + (a.m[i][k] * b.m[k][j])) % 10000;
return c;
}
void mul(long long n)
{
matrix res,a;
for(int i = 0;i < 2;i++)
for(int j = 0;j < 2;j++)
res.m[i][j] = i==j?1:0;
a.m[0][0] = 1;
a.m[0][1] = 1;
a.m[1][0] = 1;
a.m[1][1] = 0;
while(n > 0)
{
if((n&1))
res = multiply(res,a);
a = multiply(a,a);
n >>= 1;
}
cout<<res.m[0][1];
}
这道题则是快速幂的矩阵运算,首先要知道矩阵是怎么进行相乘,着重看矩阵相乘。
H-神奇的函数
代码如下:
#include<iostream>
#include<cstring>
using namespace std;
struct matrix
{
int m[11][11];
};
void mul(matrix a,int n,int k);
matrix mat(matrix a,matrix b,int n)
{
matrix c;
memset(c.m,0,sizeof c.m);
for(int i = 0;i < n;i ++)
for(int j = 0;j < n;j++)
for(int k = 0;k < n;k ++)
c.m[i][j] = (c.m[i][j]+a.m[i][k]*b.m[k][j])%9973;
return c;
}
int main()
{
int T;
cin>>T;
while(T--)
{
int n,k;
cin>>n>>k;
matrix x;
for(int i = 0;i < n;i++)
for(int j = 0;j < n;j++)
cin>>x.m[i][j];
mul(x,n,k);
}
return 0;
}
void mul(matrix a,int n,int k)
{
matrix res;
for(int i = 0;i < n;i++)
for(int j = 0;j < n;j++)
res.m[i][j]= i==j?1:0;
while(k>0)
{
if((k&1))
res = mat(res,a,n);
a = mat(a,a,n);
k >>= 1;
}
int sum = 0;
for(int i = 0;i < n;i ++)
for(int j = 0;j < n;j++)
{
if((i==j))
sum = sum+res.m[i][j];
}
cout<<sum%9973<<endl;
}
这道题的构造数组时要注意大于最大取值就可以,主要也是矩阵的快速幂
B-杰米和二进制序列
这道题没有想出来,先把题目粘下来,有空再看看。