01 位运算(快速幂)??

位运算

20190702~

一、基础概念

  1. List item1.计算机中的数据(正数和负数)都是使用二进制存储的
  2. 四种运算:
与 		x & y
或 		x | y
非		| x
异或		x ^ y
  1. int型为32位 其中首位为符号位
    负数使用补码表示 -n = n取反+1
  2. 移位操作符>> :注意计算机中的移位都是算术移位,所以在进行右移的时候,需要补符号位
  3. 在初始化数组的时候 通常将其初始化为正无穷
memset(f, 0x3f, sizeof f);	//将f中的每一个字节都初始化为输入的数 所以最后为0x3f3f3f3f

在动态规划或图论中,常会使用两个数进行相加
即:0x3f3f3f3f * 2 < 0xffffffff 不会发生溢出

二、异或运算

(一)通过异或实现配偶

  1. 若数组两两组合存放,通过异或可以快速的到数组中的另外一个数字
  2. 图论的最小费用流会使用到这个思想
  3. 在数组模拟临接表中,会保留边的正向边和反向边,将正向边和反向边连续存放在一起后,计算的时候可以实现快速求值

(2、3现在还没有接触到,还不能完全理解意思,以后学完相关内容后,再回来补充)

(二)lowbit运算

  1. lowbit功能:找到一个二进制数的最低1
// E.G.  lowbit(1001011000) = 1000

  n   =  1001011000
 ~n   =  0110100111
 ~n+1 =  0110101000
 -n   =  ~n+1

//代码实现为:
int lowbit(int n)
{
	return (~n+1) & n;
或	return (-n) & n;
}

三、例题 x3

(一)求 a 的 b 次方对 p 取模的值

知识点:快速幂
题目.
其中还介绍来矩阵快速幂(现不做要求)

题目:
输入格式:三个整数a, b, p 在同一行用空格隔开
输出格式:输出一个整数,表示 a ^ b mod p 的值
数据范围:1 <= a, b, p <= 109

输入样例:3 2 7
输出样例:2

  1. 通过b的二进制对ab计算次数进行化简

37 相当于7个3相乘,所以如果直接运算,需要乘6次,此时缺点不明显,但是当次方b极大的时候,计算量过大,会造成计算时间的延长。但是从二进制思路考虑,可以通过相邻次方之间的倍数关系对次数进行化简。
7 = 111

31 = 3
32 = 9
34 = 81
这样就把6次运算化为三个数的相乘

同理213也是通过13的二进制数来找到相对应的次方,将13拆成1+4+8

211011101
b每一位二进制所对应的an1*381*340*321*31
  1. ( ab ) mod p =(m n )mod p
    若m = ( a mod p) n=(b mod p)
#include <iostream>;
using namespace std;

int main(){
   int a,b,p;          	   //C++中输入变量的值--直接使用cin输入即可
   cin >> a >> b >> p ;
   int res = 1 % p;        //先假设一个结果:新变量res(求a^b的本质是乘法 所以设res=1 ;若求a*b 其本质为加法 设res=0)
                           //%p:如果b为0 直接没有进入循环
                           //或int res = 1; 在最后输出的时候 cout << res % p
   while(b){           	   //首先考虑变量b的个位
       if(b&1) res = res * 1ll * a % p;          //b&1:判断b的个位是否为1 
                                                 /*因为a b p 的数字比较大 可能会发生溢出 
                                                   所以要改变数据类型至long long 1ll是long long类型的整数1 
                                                   通过*1ll实现数据类型的强制转换*/
                                                 //现在已经处理完个位了
       a = a * 1ll * a % p;    //在第二次循环的时候 操作b的十位 将b的十位不断平方
       b >>= 1;       //b右移1位 去掉个位
   }
   cout << res << endl;
   return 0;
}

(二)求 a 乘 b 对 p 取模的值

输入格式:第一行整数a,第二行输入整数b,第三行输入整数p
输出格式:输出一个整数,表示a*b mod p的值
数据范围:1≤a,b,p≤1018
输入样例:
3
4
5
输出样例:
2

原理同例题一

#include <iostream>
using namespace std;
typedef unsigned long long ULL;        //如何判断什么时候使用无符号数?
                                       //注意使用替换的关键字是typedef 并且最后需要加分号

int main(){
    ULL a, b, p;
    cin >> a >> b >> p;
    ULL res = 0;   
    while(b){
        if(b & 1) res = (res + a) % p;
        b >>= 1;                        //注意 >>= 中间是不能加空格的
        a = a * 2 % p;
    }
    
    cout << res << endl;
    return 0;
}

(三)最短Hanilton路径

给定一张 n 个点的带权无向图,点从 0~n-1 标号,求起点 0 到终点 n-1 的最短Hamilton路径。 Hamilton路径的定义是从 0 到 n-1 不重不漏地经过每个点恰好一次。

输入格式:第一行输入整数n
接下来n行每行n个整数,其中第i行第j个整数表示点i到j的距离(记为a[i,j])。
对于任意的x,y,z,数据保证 a[x,x]=0,a[x,y]=a[y,x] 并且 a[x,y]+a[y,z]>=a[x,z]

输出格式:输出一个整数,表示最短Hamilton路径的长度

数据范围
1≤n≤20
0≤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


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值