ACM2019暑假训练Day1 位运算与(矩阵)快速幂

位运算和(矩阵)快速幂

位运算

& 运算

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-杰米和二进制序列

这道题没有想出来,先把题目粘下来,有空再看看。
在这里插入图片描述在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值