CodeForce 986 C. AND Graph(dfs+位运算)

C. AND Graph
time limit per test
4 seconds
memory limit per test
256 megabytes
input
standard input
output
standard output

You are given a set of size mm with integer elements between 00 and 2n12n−1 inclusive. Let's build an undirected graph on these integers in the following way: connect two integers xx and yy with an edge if and only if x&y=0x&y=0. Here && is the bitwise AND operation. Count the number of connected components in that graph.

Input

In the first line of input there are two integers nn and mm (0n220≤n≤221m2n1≤m≤2n).

In the second line there are mm integers a1,a2,,ama1,a2,…,am (0ai<2n0≤ai<2n) — the elements of the set. All aiai are distinct.

Output

Print the number of connected components.

Examples
input
Copy
2 3
1 2 3
output
Copy
2
input
Copy
5 5
5 19 10 20 12
output
Copy
2
Note

Graph from first sample:

Graph from second sample:

思路:
如果我们暴力搜索m个数的话,明显会超时,所以我们考虑,如果x&y=0 ,
那么二进制下,假设x为10101,那么y就为01010(x对应位取反)的一个”子集”,
此处子集意为y中的某些1变为0,比如此时y的子集有(01010,01000,00001,00000)。 
所以对于y我们找到它所有的子集,如果某个y的子集u在a数组中,那么我们就可以把u
看作新的x再进行这种操作。 
怎么找y的所有子集呢,我们一个1一个1的消去即可,DFS每层消一个1。 
对于一个x怎么找到y呢,我们让x ^ ((1<<n) - 1)) 即可。 
对于y怎么找到某一个1并将其消去呢,y&(1<<i)可以判断出来第i位是否
为1,y^(1<<i)可以使得第i位的1变为0,其他位置不变。
代码:
#include<bits/stdc++.h>
using namespace std;
const int maxn=(1<<22)+5;
bool is[maxn],vis[maxn];
int n,m,S,a[maxn];
void dfs(int x)
{
    if(vis[x])return;
    vis[x]=1;
    if(is[x])dfs(x^S);
    for(int i=0;i<n;i++)
        if(x>>i&1) 
        dfs(x^(1<<i));
}
int main()
{
    scanf("%d%d",&n,&m);
    S=(1<<n)-1;
    for(int i=0;i<m;i++)
    {
        scanf("%d",&a[i]);
        is[a[i]]=1;
    }
    int ans=0;
    for(int i=0;i<m;i++)
    {
        if(!vis[a[i]])
        {
            ans++;vis[a[i]]=1;
            dfs(a[i]^S);
        }
    }
    printf("%d\n",ans);
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值