https://blog.csdn.net/noone0/article/details/78289517
目前没有题目链接。
题意:长度为n的序列a,选出两个元素,其或运算结果的最大值为多少,并求出a[i]|a[j]==mx的方案数?
n<=1e5,0<=a[i]<=2^17,m<=17.
假如最大值为mx,若x|y=mx 则x和y肯定为mx的子集.否则或运算结果肯定不为mx.
枚举最大值 在枚举mx的子集x. 则此时y要包含(mx-i)这个子集.(若y比mx多出某个为1的bit位 则后面最大值还会更新.)
求个数,则需要知道序列中有多少个元素有子集mask=(mx-i).
F(mask) 序列中有多少个数存在一个子集为mask,暴力O(3^m)枚举水过..
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<queue>
#include<map>
#include<vector>
#include<set>
#include<string>
#include<cmath>
#include<cstring>
#define F first
#define S second
#define ll long long
#define pb push_back
#define pm make_pair
using namespace std;
typedef pair<int,int> PII;
const int MAX = 2e5 + 5;
int a[MAX],num[MAX];
int f[MAX],a[MAX];
int main()
{int n;cin>>n;for(int i = 1; i<=n; i++) {scnf("%d",a+i);num[a[i]]++;}int up = 1<<17;for(int sta = 0; sta<up; sta++) {for(int i = sta; i; i = sta&(i-1)) {//枚举子集 f[i] += num[sta];}f[0] += num[sta];}ll ans = 0;int maxx = 0;for(int sta = 0; sta<up; sta++) {ll res = 0;for(int i = sta; i; i = sta&(i-1)) {res += num[i] * f[sta-i];}res += num[0] * f[sta];res -= num[sta];if(res) {ans = res/2;maxx = sta;}}printf("%d %d\n",maxx,ans); return 0 ;
}