CodeForces - 1368D AND, OR and square sum(位運算+貪心)

題目鏈接:點擊查看

題目大意:給出 n 個數組成的序列 a ,現在可以進行的操作是,任選兩個下標 i 和 j ,滿足 i != j ,使得:

  1. 設 x = a[ i ] , y = a[ j ]
  2. a[ i ] = x and y
  3. a[ j ] = x or y

問經過任意次操作後,a[ 1 ] * a[ 1 ] + a[ 2 ] * a[ 2 ] ... + a[ n ] * a[ n ] 的最大值是多少

題目分析:首先需要觀察出的一個前置性質就是,x + y = ( x or y ) + ( x and y ),這個對於 x 與 y 的其中一位打個表就能看出來

x 0 0 1 1
y 0 1 0 1
x&y 0 0 0 1
x|y 0 1 1 1
x+y 0 1 1 2
(x&y)+(x|y) 0 1 1 2

這個性質,換句話說,就是無論如何變化,序列 a 中每一位上的 “ 1 ” 的個數是固定的

這樣一來我們就可以貪心去處理了,如果想讓平方和最大的話,那麼顯然讓每一個數儘量大是最優的,這樣我們可以先貪心將第一個數的每一位全部賦值爲 1 ,然後再這樣貪心處理第二個、第三個等等

代碼:

#include<iostream>
#include<cstdio>
#include<string>
#include<ctime>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<stack>
#include<climits>
#include<queue>
#include<map>
#include<set>
#include<sstream>
#include<cassert>
using namespace std;

typedef long long LL;

typedef unsigned long long ull;

const int inf=0x3f3f3f3f;

const int N=1e5+100;

int cnt[30];

void solve(int num)
{
	for(int i=0;i<30;i++)
		cnt[i]+=((num>>i)&1);
}

int main()
{
#ifndef ONLINE_JUDGE
//  freopen("input.txt","r",stdin);
//  freopen("output.txt","w",stdout);
#endif
//  ios::sync_with_stdio(false);
	int n;
	scanf("%d",&n);
	for(int i=1;i<=n;i++)
	{
		int num;
		scanf("%d",&num);
		solve(num);
	}
	LL ans=0;
	for(int i=1;i<=n;i++)
	{
		LL num=0;
		for(int j=0;j<30;j++)
		{
			if(cnt[j])
			{
				cnt[j]--;
				num|=(1<<j);
			}
		}
		ans+=num*num;
	}
	printf("%lld\n",ans);


















    return 0;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章