Hihocoder 1496 寻找最大值(状态压缩 + 高位前缀和)

题目链接  Hiho 1496

设$f[i]$为二进制集合包含$i$的最大的两个数,这个东西用高维前缀和维护。

高位前缀和转移的具体方案 :枚举每一位,然后枚举每个集合,大的转移到小的。

注意合并的时候最好别用$std::sort$(我一开始被卡常数了)

#include <bits/stdc++.h>

using namespace std;

#define rep(i, a, b)	for (int i(a); i <= (b); ++i)
#define dec(i, a, b)	for (int i(a); i >= (b); --i)
#define fi		first
#define se		second

typedef long long LL;
typedef pair <int, int> PII;

int T;
int n;
int c[6];
PII f[(1 << 20) + 10];
LL  ans;


inline void up(PII &a, PII b){
	if (b.fi > a.fi){
		a.se = a.fi;
		a.fi = b.fi;
	}

	else if (b.fi > a.se){
		a.se = b.fi;
	}

	if (b.se > a.fi){
		a.se = a.fi;
		a.fi = a.se;
	}

	else if (b.se > a.se){
		a.se = b.se;
	}
}

int main(){

	scanf("%d", &T);
	while (T--){
		scanf("%d", &n);
		memset(f, -1, sizeof f);

		rep(i, 1, n){
			int x;
			scanf("%d", &x);
			if (~f[x].fi) f[x].se = x;
			else f[x].fi = x;
		}

		rep(i, 0, 19){
			rep(j, 0, (1 << 20) - 1){
				if ((1 << i) & j){
					up(f[j ^ (1 << i)], f[j]);
				}
			}
		}

		ans = 0;
		rep(i, 0, (1 << 20) - 1) if ((~f[i].fi) && (~f[i].se)) ans = max(ans, 1ll * i * f[i].fi * f[i].se);
		printf("%lld\n", ans);
	}

	return 0;
}

  

 

posted @ 2018-03-13 22:58  cxhscst2  阅读(368)  评论(3编辑  收藏  举报