D. AND, OR and square sum(贪心,感性证明,二进制)

, 3 5 011 , 101 举个例子把,比如我选3和5操作,二进制分别是011,101

& 001 , 3 二进制\&后是001,丢失了3的第二位二进制

111 , 5 二进制|后是111,增加了5的第二位二进制

! ! ! 1 ! ! 发现了什么!!!操作后二进制每一位上的1总数不变!!

, 1 那我们大胆的贪心,统计二进制每一位上的1数量

, , 1 , 然后假设最后操作完,每一个数都尽可能大,也就是只要这一位还有1,就加上去

构造正确性证明

, ? 也许你有疑问,最后能不能存在我们构造的这种结果呢?

! ! 1 肯定有!!你要记住操作不改变原有1的数量

1 , 1 只要当前构造的数还没有覆盖全部的1,就应该去和那个有1的数操作

贪心正确性证明(只是感性证明)

, 11111111111111110 01111111111111111 比如两个二进制,11111111111111110和01111111111111111

& 0 , 11111111111111111 \&后是0,|后是11111111111111111

! ! , 1 看起来好亏呀!!损失了那么大个数的平方,只增加了1

实际上计算一下发现这样还是更优的

. . . . . . . . . . 虽然这样并不能算是证明.....但是就是做题的一种方法呀.....

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=2e5+10;
ll n,a[maxn],b[maxn],xi[maxn],ans;
int main()
{
	cin >> n;
	for(int i=1;i<= n;i++)
	{
		cin >> a[i];
		int x=1;
		while(a[i])
		{
			if(a[i]&1)	b[x]++;
			a[i]>>=1;
			x++;
		}
	}
	xi[1]=1;
	for(int i=2,len=1;i<=30;i++)	len*=2, xi[i]=len;
	for(int i=1;i<=n;i++)
	{
		ll x=0;
		for(int j=1;j<=30;j++)
			if(b[j])	b[j]--,x+=xi[j];//贪心,有1就加上去 
		ans+=x*x;
	}
	cout << ans;
}

猜你喜欢

转载自blog.csdn.net/jziwjxjd/article/details/106869046