快速幂与位运算

快速幂运用分治的思想

我们先有整式乘法的定义:

x p × x k = x p + k x^p\times x^k=x^{p+k} xp×xk=xp+k

所以我们有:

x k = x ⌊ k 2 ⌋ × x ⌊ k 2 ⌋ x^k=x^{\lfloor\frac{k}{2}\rfloor}\times x^{\lfloor\frac{k}{2}\rfloor} xk=x2k×x2k

然后我们继续

x ⌊ k 2 ⌋ = x ⌊ k 4 ⌋ × x ⌊ k 4 ⌋ x^{\lfloor\frac{k}{2}\rfloor}=x^{\lfloor\frac{k}{4}\rfloor}\times x^{\lfloor\frac{k}{4}\rfloor} x2k=x4k×x4k

直到 x x x 的指数为 1 1 1,统计

然后我们就可以放上代码

【模板】快速幂||取余运算

#include<bits/stdc++.h>
#define int unsigned long long

using namespace std;

int n,m,k;
int quickfast(int a,int b) {
	int ans=1,base=a;
	while(b) {
		if(b&1) ans=(ans*base)%k;
		base=(base*base)%k; b>>=1;
	} return ans;
}
signed main()
{
	scanf("%llu%llu%llu",&n,&m,&k);
    printf("%llu",quickfast(n,m));
}

快速幂,快速幂,快速,就要用到位运算了

位运算

位运算是在二进制的基础下进行的运算

那么如何将一个十进制的数转换为二进制的数呢?

计算器

当然计算器是一个非常优秀的工具,但是有没有办法通过运算呢

比如这样的数: 12321 12321 12321

通过计算器,我们很容易得出了他的二进制数: 11000000100001 11000000100001 11000000100001

这时我们就要用到短除法(手动模拟)

d a t a data data 字符串来记录二进制,则

12321 % 2 ≠ 0 12321\%2 \neq 0 12321%2=0,记 1 1 1 ( 12321 − 1 ) ÷ 2 = 6160 (12321-1)÷2=6160 (123211)÷2=6160

6160 % 2 = 0 6160\%2=0 6160%2=0,记 0 0 0 6160 ÷ 2 = 3080 6160÷2=3080 6160÷2=3080

3080 % 2 = 0 3080\%2=0 3080%2=0,记 0 0 0 3080 ÷ 2 = 1540 3080÷2=1540 3080÷2=1540

1540 % 2 = 0 1540\%2=0 1540%2=0,记 0 0 0 1540 ÷ 2 = 770 1540÷2=770 1540÷2=770

770 % 2 = 0 770\%2=0 770%2=0,记 0 0 0 770 ÷ 2 = 385 770÷2=385 770÷2=385

385 % 2 ≠ 0 385\%2\neq0 385%2=0,记 1 1 1 ( 385 − 1 ) ÷ 2 = 192 (385-1)÷2=192 (3851)÷2=192

192 % 2 = 0 192\%2=0 192%2=0,记 0 0 0 192 ÷ 2 = 96 192÷2=96 192÷2=96

96 % 2 = 0 96\%2=0 96%2=0,记 0 0 0 96 ÷ 2 = 48 96÷2=48 96÷2=48

48 % 2 = 0 48\%2=0 48%2=0,记 0 0 0 48 ÷ 2 = 24 48÷2=24 48÷2=24

24 % 2 = 0 24\%2=0 24%2=0,记 0 0 0 24 ÷ 2 = 12 24÷2=12 24÷2=12

12 % 2 = 0 12\%2=0 12%2=0,记 0 0 0 12 ÷ 2 = 6 12÷2=6 12÷2=6

6 % 2 = 0 6\%2=0 6%2=0,记 0 0 0 6 ÷ 2 = 3 6÷2=3 6÷2=3

3 % 2 ≠ 0 3\%2\neq0 3%2=0,记 1 1 1 ( 3 − 1 ) ÷ 2 = 1 (3-1)÷2=1 (31)÷2=1

1 % 2 ≠ 0 1\%2\neq0 1%2=0,记 1 1 1 ( 1 − 1 ) ÷ 2 = 0 (1-1)÷2=0 (11)÷2=0

然后我们把所有记下的数反过来,就得到: 11000000100001 11000000100001 11000000100001

这个很容易用代码来实现

string data;
int x; cin >> x;
while(x) {
    if(x%2) data+='1',x^=1,x>>=1;
    else data+='0',x>>=1;
} reverse(data.begin(),data.end());

它的时间复杂度是 O ( l o g 2 x ) O(log^2x) O(log2x)

二进制转十进制也很简单了,就不模拟了,自行理解

string data;
int x; cin >> data;
int len=data.size();
for(int i=0;i<len;i++,x*=2) if(data[i]=='1') ++x;

左移、右移

< < << << 为位运算左移,例如二进制数: 101010 101010 101010,通过 < < << << 后,变成 1010100 1010100 1010100

> > >> >> 为位运算右移,例如二进制数: 101010 101010 101010,通过 > > >> >> 后,变成 10101 10101 10101

与、或、异或

10 10 10 的二进制数为 1010 1010 1010 12 12 12 的二进制数为 1100 1100 1100

& \& & 为与运算

运算

10 & 12 10\&12 10&12 ,则两个数的二进制,同一位上的数若都为 1 1 1,则答案那位上的数为 1 1 1,否则为 0 0 0

10 & 12 10\&12 10&12 答案就是 1000 1000 1000,也就是 8 8 8

定义

1. 1. 1. x & 0 ≡ 0 x\& 0 \equiv 0 x&00

2. 2. 2. x & 1 ≡ x % 2 x\& 1 \equiv x\%2 x&1x%2

3. 3. 3. x & x ≡ x x\& x \equiv x x&xx

∣ | 为或运算

运算

10 ∣ 12 10|12 1012 ,则两个数的二进制,同一位上的数只要有一个为 1 1 1,则答案那位上的数为 1 1 1,否则为 0 0 0

10 ∣ 12 10|12 1012 答案就是 1110 1110 1110,也就是 14 14 14

比较没用的定义

1. 1. 1. x ∣ 0 ≡ x x|0 \equiv x x0x

$ 2.x|1=
\begin{cases}
(x&1)&x+0 \
!(x&1)&x+1
\end{cases}
$

3. 3. 3. x ∣ x ≡ x x|x \equiv x xxx

^ 为异或运算

⊕ \oplus 同为异或运算
运算

10 ⊕ 12 10 \oplus 12 1012 ,则两个数的二进制,同一位上的数若不同,则答案那位上的数为 1 1 1,否则为 0 0 0

10 ⊕ 12 10\oplus12 1012 答案就是 110 110 110,也就是 6 6 6

定义

1. 1. 1. x ⊕ 0 ≡ x x \oplus 0 \equiv x x0x

$ 2.x \oplus 1=
\begin{cases}
(x&1)&x-1 \
!(x&1)&x+1
\end{cases}
$

3. 3. 3. x ⊕ x ≡ 0 x \oplus x \equiv 0 xx0

运算的优先级

⊕ \oplus 与 ~ 的优先级 高于 & \& & ∣ |

非运算:~

~ x = − x − 1 x=-x-1 x=x1

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值