2020牛客NOIP赛前集训营-提高组(第二场)B包含

it2025-01-16  4

题目

传送门

题目描述

我们定义 A A A“包含” B B B的概念是 A & B = B A\&B=B A&B=B,其中 & \& &是位运算中的“按位与”。

现在给出一个集合 Q Q Q,这个集合 n n n个正整数, m m m次询问。每次询问给出一个数字 x x x,请回答集合 Q Q Q中是否有一个数字包含 x x x

输入描述

第一行输入两个正整数 n n n m m m,意义如题面所示。接下来一行输入 n n n个正整数,描述集合 Q Q Q中的数字,其中第 i i i个数字为 a i a_i ai。然后有 m m m行,每行给出一个正整数 x x x,代表询问。

输出描述

对于每一个询问,输出 y e s yes yes n o no no表示答案。

分析

这题比较水,暴力也能过,这里不再赘述 讲讲正经思路:采取 d p dp dp

我们可以用 d p dp dp进行预处理, d p [ i ] dp[i] dp[i]代表对于询问的数字为 i i i时的答案。( 1 1 1代表包含, 0 0 0代表不包含)

首先,不难得出 A & A = A A\&A=A A&A=A,因此对于输入的所有数字 a [ i ] a[i] a[i]可得 d p [ a [ i ] ] = 1 dp[a[i]]=1 dp[a[i]]=1 然后我们倒着枚举值域,对于任意一个数字 x x x,如果 d p [ x ] = 1 dp[x]=1 dp[x]=1,那么去除其中任意一位二进制上的 1 1 1,对应的 d p dp dp值仍为 1 1 1 O ( n l o g n ) O(nlogn) O(nlogn)的时间进行预处理,之后就可以 O ( 1 ) O(1) O(1)回答每次查询了

代码

#include <bits/stdc++.h> using namespace std; const int maxn=1e6+666; int n,m,x,a[maxn],dp[maxn]; void Sc() { for(int j=0;j<20;j++) for(int i=maxn;i>=0;i--) if(dp[i]&&(i>>j&1)) dp[i-(1<<j)]=1; } int main() { scanf("%d%d",&n,&m);for(int i=1;i<=n;i++) scanf("%d",a+i),dp[a[i]]=1; Sc(); while(m--) { scanf("%d",&x); if(dp[x]) puts("yes"); else puts("no"); } }

----原创文章,仅供参考

最新回复(0)