题目:

【算法练习题】位运算(贪心)_算法

解题报告:

首先预备几个结论:

1、对于两个数a,b ,生成a&b和a|b,则一定对应一个常数c,使得生成的两个数分别是a+c和a-c。

2、对于两个数a,b,生成a&b和a|b的前后,二进制的1的个数是不变的。

基于以上两点(对于这一题,主要是第二点),我们可以简单的进行扩展这个结论,对于任意出现过的某个数位的1,都可以进行任意的排列组合。思路就是直接贪心,打散后按照贪心策略重组出最后结果,即可以生成任意一个序列,只要他们和初始序列的二进制的1的个数是一样的。

因为我们发现,对于平方和,数字集中在越少的个数上,值越大,比如(4+1)^2>4^2+1^2,以此类推,所以贪心的策略显而易见。(没有证明,猜的一个结论)

AC代码:

#include<bits/stdc++.h> 

using namespace std;
int cnt[55];
int n, mx;
int main( )
{
cin>>n;
for(int x, i = 1; i<=n; i++) {
cin>>x;
int p = 0;
while(x) {
if(x%2 == 1) cnt[p] ++;
x /= 2;
p ++;
}
mx = max(mx, p);
}
long long ans = 0;
for(int i = 0; i<n; i++) {
long long t = 0;
for(int j = 0; j<mx; j++) {
if(cnt[j] > 0) t += (1<<j), cnt[j]--;
}
ans += t * t;
}
cout << ans;
return 0;
}