題目鏈結(click)
時間限制:c/c++ 1秒,其他語言2秒
空間限制:c/c++ 262144k,其他語言524288k
64bit io format: %lld
題目描述
給定n個整數,依次為a1,a2,…,an。
求∑ i=
1n∑j
=1n(
ai&a
j)
\sum_^n\sum_^n(a_i\&a_j)
i=1∑n
j=1∑
n(a
i&a
j)'&'是二進位制與運算子。
輸入描述
第一行乙個整數n.輸出描述第二行n個整數ai.
乙個整數表示上述求和式的答案.樣例輸入
5樣例輸出備註1 2 3 4 5
1≤ n ≤1e5分析0≤ ai ≤1e8
先瞄一眼所求和式,明面上o(n2)的時間複雜度。
再看一眼資料範圍:1≤ n ≤1e5,心如死灰。
當然,acmer早已見怪不怪,縱使題目虐我千百遍,我仍待她如初戀。
咱們先好好觀察一下這「初戀」,和式中心的』&'也許是突破口,眾所周知,位運算往往用來優化時間、空間複雜度,出題人也許在這藏了什麼貓膩。
真·分析
正所謂,好記憶體不如爛硬碟 ,咳咳,我們先在紙上模擬一下這個和式。
先就 i==1 來看:
a1&a1+a1&a2+a1&a3+…+a1&an
即a1和每一項分別相與(&)再相加(+)
既然&是按位與,那麼我們就從位的角度來看,分析每一位如何變化:
假如a1的某一位是0,那麼無論相與物件的該位是什麼,相與結果皆為0,對結果無貢獻。
假如a1的某一位是1,同理,只有當相與物件該位為1時,結果才為1,貢獻為1*(該位權重)
不僅是a1,對於每乙個ai均是如此,假設特定位為第k位,所有ai該位上共有m個1
則,該位對答案的貢獻為:m*m*(1<<(k-1))
如此,只要預處理出每一位上1的個數即可,複雜度o(n)
「talk is cheap. show me the code.」
#include
#include
#include
using
namespace std;
const
int maxn =
1e5+5;
typedef
long
long ll;
int num[maxn]
;int b[31]
;//由於非負,第32位必位0
intmain
(void
)for
(int i =
0; i <
31; i++
)//貢獻彙總
ans +
=(ll)b[i]
* b[i]*(
1ll<< i)
;printf
("%lld\n"
, ans)
;return0;
}
牛客練習賽60 A 大吉大利 思維
傳送門 a 大吉大利.題目描述 給定n個整數,依次為a1 a2 an。求 i 1n j 1n ai a j sum n sum n a i a j i 1n j 1 n a i a j 是二進位制的與運算子。輸入描述 第一行乙個整數n.第二行nn個整數 ai.輸出描述 乙個整數表示上述求和式的答案....
牛客練習賽60 A 大吉大利(位運算)
給定 n nn 個整數,依次為 a1,a2,a na 1,a 2,a n a1 a2 an 求 i 1 n j 1n a i aj sum n sum n a i a j i 1n j 1 n a i a j katex parse error expected eof got at positio...
牛客練習賽60補題
思路 考慮位運算 的特性 只有兩者都為1才會對答案有貢獻 且 對答案貢獻的值為 1 k 其中k是當前1所在二進位制下的位數 所以考慮預處理每乙個位的1出現的次數 其中對每一位都會遍歷n n次 所以每一位對答案的貢獻就是 a i a i 1 i a i 為當前位置1的個數 include using ...