快速幂运用分治的思想
我们先有整式乘法的定义:
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=x⌊2k⌋×x⌊2k⌋
然后我们继续
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} x⌊2k⌋=x⌊4k⌋×x⌊4k⌋
直到 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 (12321−1)÷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 (385−1)÷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 (3−1)÷2=1
1 % 2 ≠ 0 1\%2\neq0 1%2=0,记 1 1 1, ( 1 − 1 ) ÷ 2 = 0 (1-1)÷2=0 (1−1)÷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&0≡0
2. 2. 2. x & 1 ≡ x % 2 x\& 1 \equiv x\%2 x&1≡x%2
3. 3. 3. x & x ≡ x x\& x \equiv x x&x≡x
∣ | ∣ 为或运算
运算
若 10 ∣ 12 10|12 10∣12 ,则两个数的二进制,同一位上的数只要有一个为 1 1 1,则答案那位上的数为 1 1 1,否则为 0 0 0
10 ∣ 12 10|12 10∣12 答案就是 1110 1110 1110,也就是 14 14 14
比较没用的定义
1. 1. 1. x ∣ 0 ≡ x x|0 \equiv x x∣0≡x
$ 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 x∣x≡x
^ 为异或运算
⊕ \oplus ⊕ 同为异或运算
运算
若 10 ⊕ 12 10 \oplus 12 10⊕12 ,则两个数的二进制,同一位上的数若不同,则答案那位上的数为 1 1 1,否则为 0 0 0
10 ⊕ 12 10\oplus12 10⊕12 答案就是 110 110 110,也就是 6 6 6
定义
1. 1. 1. x ⊕ 0 ≡ x x \oplus 0 \equiv x x⊕0≡x
$ 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 x⊕x≡0
运算的优先级
⊕ \oplus ⊕ 与 ~ 的优先级 高于 & \& & 与 ∣ | ∣
非运算:~
~ x = − x − 1 x=-x-1 x=−x−1