[牛客競賽] 小A的位運算(思維)

鏈接:https://ac.nowcoder.com/acm/contest/549/D
來源:牛客網

題目描述

位運算是一個非常重要的東西。而小A最近在學習位運算,小A看到了一道很簡單的例題,是說從N個數裏面選出N-1個數要讓它們或起來的值最大,小A想知道這個答案是多少。你可以幫幫他嗎?

輸入描述:

第一行一個整數N表示有N個數接下來一行N個數表示A1,A2…AN

輸出描述:

一行輸出個結果代表最大值

輸入

5
1 2 4 8 16

輸出

30

說明

選擇2,4,8,16或的和是最大的,沒有比這個更大的方案。
備註: 1 ≤ N ≤ 5e6,1 ≤ A[i] ≤ longlong



分析:

雖說是位運算,但是這題和二進制沒啥關係…

要去除N個數中的一個,使剩下的N-1個數最大,或運算的話要除去的數並沒有什麼特徵,於是要枚舉被除去的數。

O(N2)的枚舉肯定是不行的,這裏就要用到技巧了,先預處理 前 i 個數的或和後 i 個數的或和,分別放入 L[i]R[i] 中,然後枚舉被除去的數,則有

i=L[i1]R[i+1] 除去 i 後的或和 = L[i-1] | R[i+1]

該方法可適用於定義一種運算,然後求去除其中一個數然後運算後的最大/最小值。



以下代碼:

#include<bits/stdc++.h>
#define LL long long
using namespace std;
const int INF=0x3f3f3f3f;
const int maxn=5e6+10;
LL A[maxn],L[maxn],R[maxn];       //外部定義,數組全部置零
int main()
{
	int N;
	LL ans=0;
	scanf("%d",&N);
	for(int i=1;i<=N;i++)
		scanf("%lld",&A[i]);
	for(int i=1;i<=N;i++)         //注意L R的初值都是0
		L[i]=L[i-1]|A[i];         //這樣保證 起始數 與 0 或後是其本身
	for(int i=N;i>=1;i--)
		R[i]=R[i+1]|A[i];
	for(int i=1;i<=N;i++)
		ans=max(ans,L[i-1]|R[i+1]);
	printf("%lld",ans);
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章