題目大意
給定 \(n\)個非負整數,每次你可以選擇兩個數\(a,b\) ,將其中一個數變為 \(a\ and\ b\),另一個變為 \(a\ or\ b\),你可以進行多次操作,任何時候都可以停止,請最大化所有數的平方和。
輸入格式
第一行包含一個正整數 \(n\)。
第二行包含 \(n\)個用空格分開的非負整數 \(a_i\)。
輸出格式
一行一個非負整數表示最後最大化的所有數的平方和。
【輸入樣例】
5
1 2 3 4 5
【輸出樣例】
99
【樣例解釋】
一組最優方案是變成 \(7,0,7,0,1\),答案是 \(99\)。
對於\(100\%\)的資料,\(N\le10^5,a_i\le10^6\)
基本思路
位運算當然要在二進位制下考慮啦。我們先隨便拉兩個數出來\((101010)_2\) 和\((110101)_2\) 最後操作完就是 \((111111)_2\) 和\((100000)_2\) 那麼我們就發現了這個操作就是將一個數所有可以挪過去的 \(1\) 挪過去。
上過初中的都知道,\(a^2+b^2\le (a+b)^2\),所以我們把所有數摞起來,把所有 \(1\) 儘量往一個數上推就可以了。
核心程式碼
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e5+10;
int n,a,cnt[30];
ll ans;
int main(){
freopen("andor.in","r",stdin);
freopen("andor.out","w",stdout);
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
cin>>n;
for(int i=1;i<=n;i++){
cin>>a;
for(int j=0;j<=25;j++){
if(a&(1<<j))
cnt[j]++;
}
}
for(int i=1;i<=n;i++){
a=0;
for(int j=0;j<=25;j++){
if(cnt[j]>0){
cnt[j]--;
a|=(1<<j);
// cout<<j<<":"<<a<<endl;
}
}
ans+=1ll*a*a;
}
cout<<ans;
return 0;
}