题面
我们定义 A 包含 B 的概念是 A & B = B A \And B = B A&B=B,其中 & \And & 是位运算中的按位与。
现在给出一个集合 Q Q Q,这个集合中的 n n n 个正整数与 m m m 次询问。每次询问给出一个数字 x x x,请回答集合 Q Q Q 中是否有一个数字包含 x x x。
数据范围
对于 20 % 20 \% 20% 的数据,满足 n ≤ 1 0 5 , m ≤ 10 , x ≤ a i ≤ 1000 n \leq 10^5, m \leq 10, x \leq a_i \leq 1000 n≤105,m≤10,x≤ai≤1000。
对于 40 % 40 \% 40% 的数据,满足 n ≤ 1 0 5 , m ≤ 1 0 5 , x ≤ a i ≤ 1000 n \leq 10^5, m \leq 10^5, x \leq a_i \leq 1000 n≤105,m≤105,x≤ai≤1000。
对于 100 % 100 \% 100% 的数据,满足 1 ≤ n ≤ 1 0 5 , 1 ≤ m ≤ 1 0 5 , 1 ≤ x ≤ a i ≤ 1 0 6 1 \leq n \leq 10^5, 1 \leq m \leq 10^5, 1 \leq x \leq a_i \leq 10^6 1≤n≤105,1≤m≤105,1≤x≤ai≤106。
题解
考虑状压
记
f
i
f_i
fi表示状态为
i
i
i是否为
1
−
n
1-n
1−n中数的子集。然后从大到小枚举
i
i
i,从以
i
i
i为子集的
j
j
j转移来即可
代码
#include<bits/stdc++.h>
using namespace std;
inline int read(){
int k=0,f=1;
char ch;
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9')k=k*10+ch-'0',ch=getchar();
return k*f;
}
const int N=3e6+10;
int n,m,f[N],mx;
int main(){
// freopen("contain.in","r",stdin);
// freopen("contain.out","w",stdout);
n=read();m=read();
for(int i=1;i<=n;++i){
int x=read();
f[x]=1;mx=max(mx,x);
}
for(int i=mx;i>=1;--i){
int k=i;
for(int j=0;j<=20;++j){
if(!(i&(1<<j)))f[i]=max(f[i],f[i+(1<<j)]);
}
/* for(int j=10;j>=0;--j){
if(i&(1<<j))cout<<1;
else cout<<0;
}
//cout<<i<<" "<<f[i]<<endl;
cout<<" "<<f[i]<<endl;*/
}
while(m--){
int x=read();
if(f[x])printf("yes\n");
else printf("no\n");
}
return 0;
}