題目連接c++
打表+找規律算法
時間複雜度O(logN)
less
1.題意說的是給定你n位的二進制串,除了成對的(就是指那些1的個數相同或0的個數相同的),那些不成對的數有幾個。好比n爲3時,能夠有000,001,010,011,100,101,110,111這八種二進制數,其中001能夠與010配對,011能夠與110配對,剩餘的沒法再配對,因此最後輸出4。spa
2.看要求的數的範圍2<=N<=10^18
,很是大,因此說不可能暴力去作,必定存在某種規律。code
3.既然成對的就是指二進制串中1的個數相同,那麼咱們能夠用組合數的知識來解決。即從n位數中挑m位爲1,看這樣的數有幾個,若爲偶數,則說明沒有不成對的,不然說明有落單的,這時加1便可。總結得出下列公式:blog
4.公式有了,問題來了,n這麼大怎麼算。對於這種題,很大可能性說明存在某種規律,如何找到規律,就須要打表實現。能夠根據下列代碼來打表。ci
#include<bits/stdc++.h> using namespace std; typedef long long ll; /*打表*/ const int N = 1000; ll c[N][N]; int n; ll res[N]; void init() { for(int i = 0; i < N;i ++) for(int j = 0; j <= i; j++) { if(!j) c[i][j] = 1; else c[i][j] = (c[i-1][j] + c[i-1][j-1]); } } int main() { init(); for(int i = 2; i < N; i++) { for(int j = 0; j <= i; j++) { res[i] += (c[i][j] % 2); } cout << "res[" << i << "] = " << res[i] << endl; } }
因爲沒有取餘致使後面的數溢出變成負數了,不過沒有關係,咱們只須要看前面幾個數就能找到規律。get
看上面這張圖,仔細觀察顏色相同的下劃線標註的位置。好像成2的倍數的數他們的結果相同。好像還有點什麼,那麼咱們就把每一個數拆分紅二進制數,找到他們在輸出中的位置,仔細觀察。數學
將上圖中二進制數對應的結果進行比對,再與二進制數自己的特徵加以比較,發現最終的結果與n對應的二進制數中的1的個數有關。由此,得出了最終規律。it
5.總結一下,規律爲n對應的二進制數中1的個數k,答案爲2^k
。
#include<bits/stdc++.h> using namespace std; typedef long long ll; /*打表 const int N = 1000; ll c[N][N]; int n; ll res[N]; void init() { for(int i = 0; i < N;i ++) for(int j = 0; j <= i; j++) { if(!j) c[i][j] = 1; else c[i][j] = (c[i-1][j] + c[i-1][j-1]); } } int main() { init(); for(int i = 2; i < N; i++) { for(int j = 0; j <= i; j++) { res[i] += (c[i][j] % 2); } cout << "res[" << i << "] = " << res[i] << endl; } } */ ll n; int main() { cin >> n; ll res = 1; while(n) { if(n & 1) res <<= 1; n >>= 1; } cout << res ; return 0; }
代碼中求組合數的模板來源於yxc大佬的數學知識模板