a^b(位运算、快速幂思想) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 #include <iostream> using namespace std ;int main () { long long a, b, p; long long ans; cin >> a >> b >> p; ans = 1 % p; while (b) { if (b & 1 ) ans = (ans * a) % p; a = (a * a) % p; b >>= 1 ; } cout << ans << endl ; return 0 ; }
答案要求输出a^b%p。根据题目给出的范围,无法使用朴素做法。
可以将b转换成k位二进制表示形式,其中$k = \lceil {ln{(b+1)}} \rceil$。
$b = c_{k-1}2^{k-1} + … + c_{0}2^{0}$
$a^b = a^{c_{k-1}2^{k-1}} * … * a^{c_{0}2^{0}}$
ci表示b的第i位,有两种取值:0或1。
若b的第i位为1,则将$a^{2^{k-1}}$累乘到答案中。
又因为:$a^{2^i} = a^{2^{i-1}} * a^{2^{i-1}}$
我们使用a表示底数,每次计算后a = (a * a) % p。
所以我们只需要依次取b的每一位二进制数,若为1,则将a累乘到答案中。
注意:ans = 1 % p 而不是 1,是因为考虑到p = 1的特殊情况。
64位整数乘法(位运算、快速幂思想) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 #include <iostream> using namespace std ;typedef long long LL;int main () { LL a, b, p; LL ans = 0 ; cin >> a >> b >> p; while (b) { if (b & 1 ) ans = (ans % p + a % p) % p; a = 2 * a % p; b >>= 1 ; } cout << ans << endl ; return 0 ; }
答案要求输出a*b%p,其中a,b,p数量级均为long long级别。
利用快速幂的思想,将b使用二进制表示:$b = c_{k - 1}2^{k-1} + … + c_02^0$。
则$a*b = a * c_{k - 1}2^{k-1} + … + a * c_02^0$,其中$c_i$表示b二进制形式的第i位:0或1。
并且,可以递推得到$a*2^{k} = 2 * a * 2^{k-1}$。
我们使用a表示基数,每次计算后a = 2 * a。
然后依次分解b的每一位二进制数,若为1,则将计算结果累加到答案中。
起床困难综合征(位运算) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 #include <iostream> using namespace std ;typedef pair <string , int > PII;const int N = 1e5 + 10 ;int n, m;int k;PII cmd[N]; int calc (int bit, int a) { for (int i = 0 ; i < k; i++) { if (cmd[i].first == "AND" ) a &= ((cmd[i].second >> bit) & 1 ); else if (cmd[i].first == "OR" ) a |= ((cmd[i].second >> bit) & 1 ); else a ^= ((cmd[i].second >> bit) & 1 ); } return a; } int main () { cin >> n >> m; for (int i = 0 ; i < n; i++) { string str; int num; cin >> str >> num; cmd[k++] = make_pair (str, num); } int val = 0 , ans = 0 ; for (int i = 30 ; i >= 0 ; i--) { int res0 = calc(i, 0 ); int res1 = calc(i, 1 ); if (val + (1 << i) <= m && res1 > res0) val += 1 << i, ans += 1 << i; else ans += res0 << i; } cout << ans << endl ; return 0 ; }
题目给出n个位运算,要求出对任意[0, m]范围内的数,按题目要求进行位运算结果的最大值。
位运算的特点是没有进位,只影响进行运算的位。
我们使用pair保存指令,然后从最高位开始逐个考虑ans的每一位应该填的数字。
若该位填1,需满足以下条件:
该位填1后数值不超过m,否则填0。
进行位运算后,该位应该为1。否则填0。
res0表示第i位填0后该位进行位运算的结果,res1则表示第i位填1后该位进行位运算的结果。