给一个数组,里面n个数
。You are allowed to perform the following operation: choose two distinct indices 1≤i,j≤n. If before the operation ai=x, aj=y, then after the operation ai=x AND y, aj=x OR y,
然后求
最大值
设
根据AND 和 OR 操作的特点,有
实例演示一下:
等我数位板到了就补个图
所以想要操作后和变大只需要
带入可得
所以只要满足这个条件那么就执行操作,直到没有满足条件的这一对数。
但是一个一个试太多了,这样复杂度就是O(n2)了,不妥,还得再研究研究
现在我们重新审视一下这个操作在二进制层面的变化:将
中为1而
为0的位 转移到
上 并将
的1抹去,直白一点,就是
把自己分了,分给了很多个不同的
。那么,这个题实际只需要统计二进制下不同位上1的个数就可以了,然后去构造尽可能大的数。
神奇的复杂度诞生了.jpg
#pragma GCC diagnostic error "-std=c++11"
#include <bits/stdc++.h>
#define INF 0x3f3f3f3f
#define ll long long
#define Pair pair<int,int>
#define re return
#define getLen(name,index) name[index].size()
#define mem(a,b) memset(a,b,sizeof(a))
#define Make(a,b) make_pair(a,b)
#define Push(num) push_back(num)
#define rep(index,star,finish) for(register int index=star;index<finish;index++)
#define drep(index,finish,star) for(register int index=finish;index>=star;index--)
using namespace std;
template<class T> void _deb(const char *name,T val){
cout<<name<<val<<endl;
}
const int maxn=2e5+5;
int n;
int digNum[24];
int main(){
ios::sync_with_stdio(false);
cin.tie(NULL);
cin>>n;
rep(i,0,n){
int tmp;
cin>>tmp;
int pos=0;
while(tmp){
digNum[pos]+=tmp%2;
tmp/=2;
pos++;
}
}
ll ans=0;
bool add=true;
while(add){
int minNum=INT_MAX;
rep(i,0,20){
if(digNum[i]>0 && minNum>digNum[i])
minNum=digNum[i];
}
if(minNum==INT_MAX){
add=false;
continue;
}
int num=0;
rep(i,0,20){
num+=(1<<i)*(digNum[i]>0);
digNum[i]-=minNum;
}
ans+=1LL*num*num*minNum;
}
cout<<ans<<endl;
re 0;
}