0x01 位運算
定義
bit
是度量信息的單位,包含\(0\)和\(1\)兩個匯總狀態,這種操作的速度很快!!!
首先來定義一下算術位運算
與:\(and,\&\)
或:\(or,|\)
非:\(not,~\)
異或:\(xor,ˆ\)
(\(ˆ\)這個符號通常不實用)
移位運算
左移
\[1<<n = 2^n\,\,\,n<<1=2n \]
右移
算數右移
\[n>>1 = \left \lfloor \frac{n}{2.0} \right \rfloor \]
邏輯右移
略(基本上不會用到)
\(aˆb^{\,\,CH0101}\)
\[求a的b次方對p取模的值,其中1\leq a,b,p \leq10^9 \]
標准算法(跟位運算無關)
#include <iostream>
using namespace std;
int main()
{
int a, b, p;
cin >> a >> b >> p;
unsigned long long ans = 1;
for (int i = 0; i < b; i++)
{
ans *= a;
ans %= p;
}
cout << ans << endl;
return 0;
}
如果去評測:恭喜你
TLE
因為大數據肯定超時。
於是就需要快速冪!
long long power(int a,int b,int p){
int ans = 1%p;
for(;b;b>>=1)
//for(;b;b/2.0)
{
if(b&1)ans = (long long)ans*a%p;
a=(long long)a*a%p;
}
return ans;
}
問題又來了,如果遇到這道題
\(64\text{位整數乘法}^{CH0102}\)
\[求a的b次方對p取模的值,其中1\leq a,b,p \leq10^{20} \]
那就不香了,連\(long\,\,long\)都存不下了,那就尷尬了。
方法一
類似於快速冪,把\(b\)用二進制表示,得到結果。
\[b = c_{k-1}\cdot 2^{n-1} + c_{k-2}\cdot 2^{n-2} + \cdots + c_{0}\cdot 2^{0} \]
\[\text{於是}a\cdot b = c_{k-1}\cdot 2^{n-1} \cdot a + c_{k-1}\cdot 2^{n-1} \cdot a + \cdots +c_{0}\cdot 2^{0} \cdot a \]
\[\because a\cdot 2^i = (a\cdot 2^{i-1})\cdot 2 \text{在運算時每一項都不會超過}2 \cdot 10^{18} \]
\[\therefore \text{這種方法很香啊,而且時間復雜度是} O(log_2 b)!!! \]
#define ll long long
ll mul(ll a, ll b, ll c){
long long ans = 0;
for(; b; b >>= 1){
if (b & 1) ans = (ans + a) % p;
a = a * 2 % p;
}
return ans;
}
方法二
利用$ a\cdot b,,mod,,p =,,a,,*,,b ,,-,,\lfloor \frac{a\cdot b}{p} \rfloor \cdot p$ 這個公式。
首先, \(a , b \le p\) 時,這個可以直接完成運算,英文我們不需要其他的精度位,而如果數據很大,只需要考慮比較低位的數據,那就很香了。
#define ll long long
ll mul(ll a, ll b, ll c){
a %= p, b %= p;
ll c = (long double) a * b / p;
ll ans = a * b - c * p
if (ans < 0) ans += p;
else if (ans >= p) ans -= p;
return ans;
}