基礎演算法題——異或和之和(位運算、組合數)
異或和之和
解題思路
解題方案
暴力列舉:時間複雜度:O(n3),超時。
位操作+組合數:解鈴還須繫鈴人。對於這種與、或、異或的位操作,一般也是通過位操作來解答。
總結規律
題目要求在 n 個正整數中列舉 3 個數進行位操作,若要確定 3 個數的異或結果,就要尋找對異或結果的位有影響的情況。
列舉可能情況:
0 ^ 0 ^ 0 = 0
0 ^ 0 ^ 1 = 1
0 ^ 1 ^ 0 = 1
0 ^ 1 ^ 1 = 0
1 ^ 0 ^ 0 = 1
1 ^ 0 ^ 1 = 0
1 ^ 1 ^ 0 = 0
1 ^ 1 ^ 1 = 1
①、當 3 個都為 1 時,異或的結果為 1 。
②、當 2 個為 0 時,異或結果為 1 。
③、除了 ①、② 外,其餘情況為 0 。
程式碼解析
①、列舉每一位二進位制數的值,先對 mod 求餘防止溢位。
eg:1(1), 2(10), 4(100), 8(1000)…
f[0]=1;
for(int i=1; i<64; i++)
f[i] = (f[i-1]<<1)%mod;
②、統計 n 個整數的每一位 1 的個數及 0 的個數。
0 的個數 = n - 1 的個數。可以不必再求。
//統計 n 個整數每一位為 1 的數量
//eg:num[j]: n 個整數第 j 位為 1 的數量
for(int i=0; i<n; i++){
ll tmp;
scanf("%lld", &tmp);
for(int j=0; j<64; j++)
num_1[j] += (tmp>>j)&1;
}
③、計算出每一位異或和結果能夠得到多少個 1 ( k ) ,最後將答案與該位大小 * 1 的個數( f [ i ] * k ) 累加起來,並求餘。
for(int i=0; i<64; i++){
ll one=num_1[i], zero=n-num_1[i], k;
//1 0 0 | 0 1 0 | 0 0 1
if(zero>=2 && one>=1){
k = zero*(zero-1)*one/2%mod;
ans = (ans+k*f[i]%mod)%mod;
}
//1 1 1
if(one>=3){
k = one*(one-1)*(one-2)/6%mod;
ans = (ans+k*f[i]%mod)%mod;
}
}
注意優先順序 :
‘*’、’/’ > ‘+’、’-’ > ‘%’ > ‘<<’、’>>’ > ‘=’
實現程式碼
#include<bits/stdc++.h>
#define ll long long
using namespace std;
ll ans=0;
int f[64]={0}, num_1[64]={0};
const int mod = 1e9+7;
int main(){
int n;
scanf("%d", &n);
f[0]=1;
for(int i=1; i<64; i++)
f[i] = (f[i-1]<<1)%mod;
//<<優先順序小於 mod
for(int i=0; i<n; i++){
ll tmp;
scanf("%lld", &tmp);
for(int j=0; j<64; j++)
num_1[j] += (tmp>>j)&1;
}
for(int i=0; i<64; i++){
ll one=num_1[i], zero=n-num_1[i], k;
//0 0 1
if(zero>=2 && one>=1){
k = zero*(zero-1)*one/2%mod;
ans = (ans+k*f[i]%mod)%mod;
}
//1 1 1
if(one>=3){
k = one*(one-1)*(one-2)/6%mod;
ans = (ans+k*f[i]%mod)%mod;
}
}
//優先順序 :
//'*'、'/' > '+'、'-' > '%' > '<<'、'>>' > '='
printf("%lld", ans);
return 0;
}
總結
位操作對於異或、與、或等位運算是十分有效的。
相關文章
- 位運算-異或(^)
- 計算機基礎:位運算計算機
- java中與運算,或運算,異或運算,取反運算Java
- 位與,位或,位異或運算子的理解
- JAVA基礎提高之位運算Java
- 異或運算 XOR 教程
- JavaScript ^ 按位異或運算子JavaScript
- 演算法學習筆記(16): 組合數學基礎演算法筆記
- 演算法題:三數之和演算法
- Java 基礎 之 算數運算子Java
- javascript基礎(算數運算子)(八)JavaScript
- 3D數學基礎-向量運算基礎和矩陣變換3D矩陣
- 異或運算完成數的交換, a++與++a的區別
- 深入理解按位異或運算子
- 05-JavaScript基礎-算數運算子JavaScript
- 一道位運算的演算法題演算法
- java和php基礎部分相同或異同JavaPHP
- 【演算法】位運算技巧演算法
- 【每日演算法】位運算演算法
- 演算法之位運算演算法
- js運算元組中資料排列組合JS
- 挑戰演算法題:四數之和演算法
- Java基礎06 組合Java
- [shell基礎]——算術運算
- Oracle分割槽表基礎運維-05組合分割槽Oracle運維
- 【刷題1】LeetCode 39. 組合總和 java基礎LeetCodeJava
- 運算整數C/C++位運算技巧C++
- 組合數問題
- 演算法之美 : 位運算演算法
- Java的位運算子詳解例項——與(&)、非(~)、或(|)、異或(^)Java
- Java程式設計基礎03——進位制運算&資料型別&變數Java程式設計資料型別變數
- Python基礎學習篇-2-數值運算和字串Python字串
- 位運算實現整數與位元組陣列轉換陣列
- 在C#中對列舉進行位運算--列舉組合C#
- 計算組合數 (sdut oj)
- 處理器運算位數
- python系列--計算異或和Python
- 組合數字首和