時間限制 : 10000 MS 空間限制 : 2200 KB 問題描述
給你n個整數,裡面有很多重複的數。其中只有一個數出現了3k+1次,其他都是3的倍數次。現在要你找出這個數。 輸入格式
第一行一個整數n。
第二行n個整數。 輸出格式
一個正整數,出現3k+1次的那個數。 範例輸入1
7
2 7 4 2 7 2 7 範例輸出1
4 範例輸入2
10
7 8 8 7 7 8 2 8 2 2 範例輸出2
8 提示
1<=n<=10^6,顯然n是一個3k+1型的數
0<=每個數<=10^18
注意記憶體限制。 題解
題目本身很水,隨便開個map什麼的就可過,然而本題記憶體限制只有2M……
回憶一個經典的例題,一個數列中只有一個數出現了奇數次,其他數都出現了偶數次,求這個出現奇數次的數。比較經典的做法是使用位元運算中的異或運算,把所有數異或起來,所得的數就是答案。這個演算法的實質是將每個數二進位化,一個數出現多少次其每一位的1就出現多少次,再結合異或運算的性質,便得解了。類比這種思想,我們開三個變數 a0,a1,a2 a 0 , a 1 , a 2 a_0,a_1,a_2分別記錄出現次數模3為0,1,2的二進位位有那些,那麼加入一個數 x x x可得轉移(其他幾個類似): a0=(a0 xor (a0 and x)) or (a2 and x) a 0 = ( a 0 x o r ( a 0 a n d x ) ) o r ( a 2 a n d x ) a_0=(a_0\ xor\ (a_0\ and\ x))\ or\ (a_2\ and\ x)依次加入數列中的每一個數就得解了。本題也用到了類似狀態壓縮的思想,也說明 二進位可離線處理一些數字出現次數的問題。
代碼
#include<stdio.h>using namespace std;typedef long long ll;ll n,x,a0,a1,a2,t0,t1,t2;int main(){ scanf("%lld",&n),a0=(1ll<<62)-1; while(n--) { scanf("%lld",&x); t0=(a0^(a0&x))|(a2&x); t1=(a1^(a1&x))|(a0&x); t2=(a2^(a2&x))|(a1&x); a0=t0,a1=t1,a2=t2; } printf("%lld\n",a1); return 0;}