#include <bits/stdc++.h>
#include <bitset>

#define REP(i,n) for(int i=0;i<(int)n;i++)
#define REP1(i,j,n) for(int i=j;i<(int)n;i++)
#define pb(x) push_back(x)
#define fi first
#define se second
#define all(x) x.begin(),x.end()
#define double long double
#define mp(x,y) make_pair(x,y)

typedef long long ll;

using namespace std;
class UnionFind {                                              // OOP style
public:
	vector<int> p, rank, setSize;                       // remember: vi is vector<int>
	int numSets;

public:
  void build(int N) {
    setSize.assign(N, 1); numSets = N; rank.assign(N, 0);
    p.assign(N, 0); for (int i = 0; i < N; i++) p[i] = i; }
  int findSet(int i) { return (p[i] == i) ? i : (p[i] = findSet(p[i])); }
  bool isSameSet(int i, int j) { return findSet(i) == findSet(j); }
  void unionSet(int i, int j) {
    if (!isSameSet(i, j)) { numSets--;
    int x = findSet(i), y = findSet(j);
    // rank is used to keep the tree short
    if (rank[x] > rank[y]) { p[y] = x; setSize[x] += setSize[y]; }
    else                   { p[x] = y; setSize[y] += setSize[x];
                             if (rank[x] == rank[y]) rank[y]++; } } }
  int numDisjointSets() { return numSets; }
  int sizeOfSet(int i) { return setSize[findSet(i)]; }
};
// 4194304=4e6
const int N=5e6;
int a[N];
int n,m;
int mp[N];
int fir[N];
UnionFind uf;
int all;
void go(int x){
	int mask=x^all;
	queue<int>md;
	for (int maskCpy=mask;;maskCpy=(maskCpy-1)&mask){
		if(fir[maskCpy]!=-1){
			// printf("%d %d %d\n", x,fir[maskCpy],maskCpy);
			uf.unionSet(mp[x],mp[fir[maskCpy]]);
			break;
		}
        if(mp[maskCpy]!=-1){
        	uf.unionSet(mp[x],mp[maskCpy]);
        	fir[maskCpy]=x;
        	while((int)md.size()){
        		fir[md.front()]=x;
        		md.pop();
        	}
        }else md.push(maskCpy);
        if (maskCpy == 0) break;
    }
}

int main() {
    #ifndef ONLINE_JUDGE
    freopen("in.txt","r",stdin);
    #endif

	memset(mp,-1,sizeof mp);
    scanf("%d %d",&n,&m);
    all=(1<<n)-1;
    uf.build(m);
    memset(fir,-1,sizeof fir);

    REP(i,m){
    	scanf("%d",a+i);
    	mp[a[i]]=i;
    }
    // printf("asdf\n");
	REP(i,m){
		go(a[i]);
	}
	int r=0;
	REP(i,m)r+=uf.p[i]==i;
	printf("%d\n", r);
    return 0;
}


#include <bits/stdc++.h>
#include <bitset>

#define REP(i,n) for(int i=0;i<(int)n;i++)
#define REP1(i,j,n) for(int i=j;i<(int)n;i++)
#define pb(x) push_back(x)
#define fi first
#define se second
#define all(x) x.begin(),x.end()
#define double long double
#define mp(x,y) make_pair(x,y)

typedef long long ll;

using namespace std;
class UnionFind {                                              // OOP style
public:
	vector<int> p, rank, setSize;                       // remember: vi is vector<int>
	int numSets;

public:
  void build(int N) {
    setSize.assign(N, 1); numSets = N; rank.assign(N, 0);
    p.assign(N, 0); for (int i = 0; i < N; i++) p[i] = i; }
  int findSet(int i) { return (p[i] == i) ? i : (p[i] = findSet(p[i])); }
  bool isSameSet(int i, int j) { return findSet(i) == findSet(j); }
  void unionSet(int i, int j) {
    if (!isSameSet(i, j)) { numSets--;
    int x = findSet(i), y = findSet(j);
    // rank is used to keep the tree short
    if (rank[x] > rank[y]) { p[y] = x; setSize[x] += setSize[y]; }
    else                   { p[x] = y; setSize[y] += setSize[x];
                             if (rank[x] == rank[y]) rank[y]++; } } }
  int numDisjointSets() { return numSets; }
  int sizeOfSet(int i) { return setSize[findSet(i)]; }
};
// 4194304=4e6
const int N=5e6;
int a[N];
int n,m;
int mp[N];
int fir[N];
UnionFind uf;
int all;
bool go(int msk,int x){
	if(msk==0)return 0;
	if(fir[msk]==-2)return 0;
	if(fir[msk]!=-1){
		uf.unionSet(mp[msk],mp[x]);
		return 1;
	}
	bool f=0;
	for(int i=0;i<n;i++)
		if(((1<<i)&msk)!=0){
			f|=go(msk^(1<<i),x);
		}

	if(mp[msk]!=-1)f=1;
	if(f){
		fir[msk]=x;
		uf.unionSet(mp[x],mp[msk]);
	}else fir[msk]=-2;
	return f;
}

int main() {
    #ifndef ONLINE_JUDGE
    freopen("in.txt","r",stdin);
    #endif

	memset(mp,-1,sizeof mp);
    scanf("%d %d",&n,&m);
    all=(1<<n)-1;
    uf.build(m);
    memset(fir,-1,sizeof fir);

    REP(i,m){
    	scanf("%d",a+i);
    	mp[a[i]]=i;
    	if(a[i]==0){
    		printf("1\n");
    		return 0;
    	}
    }
    // printf("asdf\n");
	REP(i,m){
		if(fir[a[i]]==-1)go(a[i]^all,a[i]);
	}
	int r=0;
	REP(i,m)r+=uf.p[i]==i;
	printf("%d\n", r);
    return 0;
}


#include <bits/stdc++.h>
#include <bitset>

#define REP(i,n) for(int i=0;i<(int)n;i++)
#define REP1(i,j,n) for(int i=j;i<(int)n;i++)
#define pb(x) push_back(x)
#define fi first
#define se second
#define all(x) x.begin(),x.end()
#define double long double
#define mp(x,y) make_pair(x,y)

typedef long long ll;

using namespace std;
class UnionFind {                                              // OOP style
public:
	vector<int> p, rank, setSize;                       // remember: vi is vector<int>
	int numSets;

public:
  void build(int N) {
    setSize.assign(N, 1); numSets = N; rank.assign(N, 0);
    p.assign(N, 0); for (int i = 0; i < N; i++) p[i] = i; }
  int findSet(int i) { return (p[i] == i) ? i : (p[i] = findSet(p[i])); }
  bool isSameSet(int i, int j) { return findSet(i) == findSet(j); }
  void unionSet(int i, int j) {
    if (!isSameSet(i, j)) { numSets--;
    int x = findSet(i), y = findSet(j);
    // rank is used to keep the tree short
    if (rank[x] > rank[y]) { p[y] = x; setSize[x] += setSize[y]; }
    else                   { p[x] = y; setSize[y] += setSize[x];
                             if (rank[x] == rank[y]) rank[y]++; } } }
  int numDisjointSets() { return numSets; }
  int sizeOfSet(int i) { return setSize[findSet(i)]; }
};
// 4194304=4e6
const int N=5e6;
int a[N];
int n,m;
int mp[N];
int fir[N];
UnionFind uf;
int nxt[N];

void go(int x){
	int mask=0;
	REP(i,n)
		if(((1<<i)&x)==0)
			mask|=1<<i;

	for (int maskCpy = mask; ; maskCpy = (maskCpy - 1) & mask) {
		if(fir[maskCpy]!=-1){
			uf.unionSet(mp[x],fir[maskCpy]);
			break;
		}

        if(mp[maskCpy]!=-1){
        	uf.unionSet(mp[x],mp[maskCpy]);
        	fir[maskCpy]=uf.findSet(mp[x]);
        }

        if (maskCpy == 0) break;
    }
    // // printf("%d\n", md.size());
    // for(int xx:md){
    // 	if(xx)
    // 	fir[xx]=mp[x];
    // }
}

int main() {
    #ifndef ONLINE_JUDGE
    freopen("in.txt","r",stdin);
    #endif

	memset(mp,-1,sizeof mp);
	memset(nxt,-1,sizeof nxt);
    scanf("%d %d",&n,&m);
    uf.build(m);
    memset(fir,-1,sizeof fir);

    REP(i,m){
    	scanf("%d",a+i);
    	mp[a[i]]=i;
    }
    // printf("asdf\n");
	REP(i,m){
		go(a[i]);
	}
	printf("%d\n", uf.numSets);
    return 0;
}


#include <bits/stdc++.h>
#include <bitset>

#define REP(i,n) for(int i=0;i<(int)n;i++)
#define REP1(i,j,n) for(int i=j;i<(int)n;i++)
#define pb(x) push_back(x)
#define fi first
#define se second
#define all(x) x.begin(),x.end()
#define double long double
#define mp(x,y) make_pair(x,y)

typedef long long ll;

using namespace std;
class UnionFind {                                              // OOP style
public:
	vector<int> p, rank, setSize;                       // remember: vi is vector<int>
	int numSets;

public:
  void build(int N) {
    setSize.assign(N, 1); numSets = N; rank.assign(N, 0);
    p.assign(N, 0); for (int i = 0; i < N; i++) p[i] = i; }
  int findSet(int i) { return (p[i] == i) ? i : (p[i] = findSet(p[i])); }
  bool isSameSet(int i, int j) { return findSet(i) == findSet(j); }
  void unionSet(int i, int j) {
    if (!isSameSet(i, j)) { numSets--;
    int x = findSet(i), y = findSet(j);
    // rank is used to keep the tree short
    if (rank[x] > rank[y]) { p[y] = x; setSize[x] += setSize[y]; }
    else                   { p[x] = y; setSize[y] += setSize[x];
                             if (rank[x] == rank[y]) rank[y]++; } } }
  int numDisjointSets() { return numSets; }
  int sizeOfSet(int i) { return setSize[findSet(i)]; }
};
// 4194304=4e6
const int N=5e6;
int a[N];
int n,m;
int mp[N];
int fir[N];
UnionFind uf;
int all;
bool go(int msk,int x){
	if(msk==0)return 0;
	if(fir[msk]==-2)return 0;
	if(fir[msk]!=-1){
		uf.unionSet(mp[fir[msk]],mp[x]);
		return 1;
	}
	bool f=0;
	for(int i=0;i<n;i++)
		if(((1<<i)&msk)!=0){
			f|=go(msk^(1<<i),x);
		}

	if(mp[msk]!=-1){
		f=1;
		uf.unionSet(mp[x],mp[msk]);
	}
	if(f){
		fir[msk]=x;
	}else fir[msk]=-2;
	return f;
}

int main() {
    #ifndef ONLINE_JUDGE
    freopen("in.txt","r",stdin);
    #endif

	memset(mp,-1,sizeof mp);
    scanf("%d %d",&n,&m);
    all=(1<<n)-1;
    uf.build(m);
    memset(fir,-1,sizeof fir);

    REP(i,m){
    	scanf("%d",a+i);
    	mp[a[i]]=i;
    	if(a[i]==0){
    		printf("1\n");
    		return 0;
    	}
    }
    // printf("asdf\n");
	REP(i,m){
		if(fir[a[i]]==-1)go(a[i]^all,a[i]);
	}
	int r=0;
	REP(i,m)r+=uf.p[i]==i;
	printf("%d\n", r);
    return 0;
}


#include <bits/stdc++.h>
#include <bitset>

#define REP(i,n) for(int i=0;i<(int)n;i++)
#define REP1(i,j,n) for(int i=j;i<(int)n;i++)
#define pb(x) push_back(x)
#define fi first
#define se second
#define all(x) x.begin(),x.end()
#define double long double
#define mp(x,y) make_pair(x,y)

typedef long long ll;

using namespace std;
class UnionFind {                                              // OOP style
public:
	vector<int> p, rank, setSize;                       // remember: vi is vector<int>
	int numSets;

public:
  void build(int N) {
    setSize.assign(N, 1); numSets = N; rank.assign(N, 0);
    p.assign(N, 0); for (int i = 0; i < N; i++) p[i] = i; }
  int findSet(int i) { return (p[i] == i) ? i : (p[i] = findSet(p[i])); }
  bool isSameSet(int i, int j) { return findSet(i) == findSet(j); }
  void unionSet(int i, int j) {
    if (!isSameSet(i, j)) { numSets--;
    int x = findSet(i), y = findSet(j);
    // rank is used to keep the tree short
    if (rank[x] > rank[y]) { p[y] = x; setSize[x] += setSize[y]; }
    else                   { p[x] = y; setSize[y] += setSize[x];
                             if (rank[x] == rank[y]) rank[y]++; } } }
  int numDisjointSets() { return numSets; }
  int sizeOfSet(int i) { return setSize[findSet(i)]; }
};
// 4194304=4e6
const int N=5e6;
int a[N];
int n,m;
int mp[N];
int fir[N];
UnionFind uf;
int all;
bool go(int msk,int x){
	if(msk==0)return 0;
	if(fir[msk]==-2)return 0;
	if(fir[msk]!=-1){
		uf.unionSet(mp[fir[msk]],mp[x]);
		return 1;
	}
	bool f=0;
	for(int i=0;i<n;i++)
		if(((1<<i)&msk)!=0){
			f|=go(msk^(1<<i),x);
		}

	if(mp[msk]!=-1){
		f=1;
		uf.unionSet(mp[x],mp[msk]);
	}
	if(f){
		fir[msk]=x;
	}else fir[msk]=-2;
	return f;
}

int main() {
    #ifndef ONLINE_JUDGE
    freopen("in.txt","r",stdin);
    #endif

	memset(mp,-1,sizeof mp);
    scanf("%d %d",&n,&m);
    all=(1<<n)-1;
    uf.build(m);
    memset(fir,-1,sizeof fir);

    REP(i,m){
    	scanf("%d",a+i);
    	mp[a[i]]=i;
    	if(a[i]==0){
    		printf("1\n");
    		return 0;
    	}
    }
    // printf("asdf\n");
	REP(i,m){
		go(a[i]^all,a[i]);
	}
	int r=0;
	REP(i,m)r+=uf.p[i]==i;
	printf("%d\n", r);
    return 0;
}


#include <bits/stdc++.h>
#include <bitset>

#define REP(i,n) for(int i=0;i<(int)n;i++)
#define REP1(i,j,n) for(int i=j;i<(int)n;i++)
#define pb(x) push_back(x)
#define fi first
#define se second
#define all(x) x.begin(),x.end()
#define double long double
#define mp(x,y) make_pair(x,y)

typedef long long ll;

using namespace std;
class UnionFind{
public:
  vector<int>p,rank,setSize;
  int numSets;
  void build(int N){
    setSize.assign(N,1);
    numSets=N;
    rank.assign(N,0);
    p.assign(N,0);
    for(int i=0;i<N;i++)p[i]=i;
  }
  int findSet(int i){return(p[i]==i)?i:(p[i]=findSet(p[i]));}
  bool isSameSet(int i,int j){return findSet(i)==findSet(j);}
  void unionSet(int i,int j){
    if(!isSameSet(i,j)){
        numSets--;
        int x=findSet(i),y=findSet(j);
        if(rank[x]>rank[y]){p[y]=x;setSize[x]+=setSize[y];}
        else{
            p[x]=y;setSize[y]+=setSize[x];
           if(rank[x]==rank[y])rank[y]++;
        }
    }
  }
  int numDisjointSets(){return numSets;}
  int sizeOfSet(int i){return setSize[findSet(i)];}
};

const int N=5e6;
int a[N];
int n,m;
int mp[N];
int fir[N];
UnionFind uf;
int all;
bool go(int msk,int x){
	if(msk==0)return 0;
	if(fir[msk]==-2)return 0;
	if(fir[msk]!=-1){
		uf.unionSet(mp[fir[msk]],mp[x]);
		return 1;
	}
	bool f=0;
	for(int i=0;i<n;i++)
		if(((1<<i)&msk)!=0){
			f|=go(msk^(1<<i),x);
		}

	if(mp[msk]!=-1){
		f=1;
		uf.unionSet(mp[x],mp[msk]);
	}
	if(f){
		fir[msk]=x;
	}else fir[msk]=-2;
	return f;
}

int main() {
    #ifndef ONLINE_JUDGE
    freopen("in.txt","r",stdin);
    #endif

	memset(mp,-1,sizeof mp);
    scanf("%d %d",&n,&m);
    all=(1<<n)-1;
    uf.build(m);
    memset(fir,-1,sizeof fir);

    REP(i,m){
    	scanf("%d",a+i);
    	mp[a[i]]=i;
    	if(a[i]==0){
    		printf("1\n");
    		return 0;
    	}
    }
    // printf("asdf\n");
	REP(i,m){
		go(a[i]^all,a[i]);
	}
	int r=0;
	REP(i,m)r+=uf.p[i]==i;
	printf("%d\n", r);
    return 0;
}


#include <bits/stdc++.h>
#include <bitset>

#define REP(i,n) for(int i=0;i<(int)n;i++)
#define REP1(i,j,n) for(int i=j;i<(int)n;i++)
#define pb(x) push_back(x)
#define fi first
#define se second
#define all(x) x.begin(),x.end()
#define double long double
#define mp(x,y) make_pair(x,y)

typedef long long ll;

using namespace std;
class UnionFind {                                              // OOP style
public:
	vector<int> p, rank, setSize;                       // remember: vi is vector<int>
	int numSets;

public:
  void build(int N) {
    setSize.assign(N, 1); numSets = N; rank.assign(N, 0);
    p.assign(N, 0); for (int i = 0; i < N; i++) p[i] = i; }
  int findSet(int i) { return (p[i] == i) ? i : (p[i] = findSet(p[i])); }
  bool isSameSet(int i, int j) { return findSet(i) == findSet(j); }
  void unionSet(int i, int j) {
    if (!isSameSet(i, j)) { numSets--;
    int x = findSet(i), y = findSet(j);
    // rank is used to keep the tree short
    if (rank[x] > rank[y]) { p[y] = x; setSize[x] += setSize[y]; }
    else                   { p[x] = y; setSize[y] += setSize[x];
                             if (rank[x] == rank[y]) rank[y]++; } } }
  int numDisjointSets() { return numSets; }
  int sizeOfSet(int i) { return setSize[findSet(i)]; }
};
// 4194304=4e6
const int N=5e6;
int a[N];
int n,m;
int mp[N];
int fir[N];
UnionFind uf;
int nxt[N];

void go(int x){
	int mask=0;
	REP(i,n)
		if(((1<<i)&x)==0)
			mask|=1<<i;

	for (int maskCpy=mask;;maskCpy=(maskCpy-1)&mask){
		if(fir[maskCpy]!=-1){
			uf.unionSet(mp[x],fir[maskCpy]);
			break;
		}
        if(mp[maskCpy]!=-1){
        	uf.unionSet(mp[x],mp[maskCpy]);
        	fir[maskCpy]=uf.findSet(mp[x]);
        }
        if (maskCpy == 0) break;
    }
}

int main() {
    #ifndef ONLINE_JUDGE
    freopen("in.txt","r",stdin);
    #endif

	memset(mp,-1,sizeof mp);
	memset(nxt,-1,sizeof nxt);
    scanf("%d %d",&n,&m);
    uf.build(m);
    memset(fir,-1,sizeof fir);

    REP(i,m){
    	scanf("%d",a+i);
    	mp[a[i]]=i;
    }
    // printf("asdf\n");
	REP(i,m){
		go(a[i]);
	}
	int r=0;
	REP(i,m)r+=uf.p[i]==i;
	printf("%d\n", r);
    return 0;
}


#include <bits/stdc++.h>
#include <bitset>

#define REP(i,n) for(int i=0;i<(int)n;i++)
#define REP1(i,j,n) for(int i=j;i<(int)n;i++)
#define pb(x) push_back(x)
#define fi first
#define se second
#define all(x) x.begin(),x.end()
#define double long double
#define mp(x,y) make_pair(x,y)

typedef long long ll;

using namespace std;
class UnionFind {                                              // OOP style
public:
	vector<int> p, rank, setSize;                       // remember: vi is vector<int>
	int numSets;

public:
  void build(int N) {
    setSize.assign(N, 1); numSets = N; rank.assign(N, 0);
    p.assign(N, 0); for (int i = 0; i < N; i++) p[i] = i; }
  int findSet(int i) { return (p[i] == i) ? i : (p[i] = findSet(p[i])); }
  bool isSameSet(int i, int j) { return findSet(i) == findSet(j); }
  void unionSet(int i, int j) {
    if (!isSameSet(i, j)) { numSets--;
    int x = findSet(i), y = findSet(j);
    // rank is used to keep the tree short
    if (rank[x] > rank[y]) { p[y] = x; setSize[x] += setSize[y]; }
    else                   { p[x] = y; setSize[y] += setSize[x];
                             if (rank[x] == rank[y]) rank[y]++; } } }
  int numDisjointSets() { return numSets; }
  int sizeOfSet(int i) { return setSize[findSet(i)]; }
};
// 4194304=4e6
const int N=5e6;
int a[N];
int n,m;
int mp[N];
int fir[N];
UnionFind uf;
int nxt[N];

void go(int x){
	int mask=0;
	REP(i,n)
		if(((1<<i)&x)==0)
			mask|=1<<i;

	for (int maskCpy=mask;;maskCpy=(maskCpy-1)&mask){
		if(fir[maskCpy]!=-1){
			uf.unionSet(mp[x],mp[maskCpy]);
			break;
		}
        if(mp[maskCpy]!=-1){
        	uf.unionSet(mp[x],mp[maskCpy]);
        	fir[maskCpy]=uf.findSet(mp[x]);
        }
        if (maskCpy == 0) break;
    }
}

int main() {
    #ifndef ONLINE_JUDGE
    freopen("in.txt","r",stdin);
    #endif

	memset(mp,-1,sizeof mp);
	memset(nxt,-1,sizeof nxt);
    scanf("%d %d",&n,&m);
    uf.build(m);
    memset(fir,-1,sizeof fir);

    REP(i,m){
    	scanf("%d",a+i);
    	mp[a[i]]=i;
    }
    // printf("asdf\n");
	REP(i,m){
		go(a[i]);
	}
	int r=0;
	REP(i,m)r+=uf.p[i]==i;
	printf("%d\n", r);
    return 0;
}


#include <bits/stdc++.h>
#include <bitset>

#define REP(i,n) for(int i=0;i<(int)n;i++)
#define REP1(i,j,n) for(int i=j;i<(int)n;i++)
#define pb(x) push_back(x)
#define fi first
#define se second
#define all(x) x.begin(),x.end()
#define double long double
#define mp(x,y) make_pair(x,y)

typedef long long ll;

using namespace std;
class UnionFind {                                              // OOP style
public:
	vector<int> p, rank, setSize;                       // remember: vi is vector<int>
	int numSets;

public:
  void build(int N) {
    setSize.assign(N, 1); numSets = N; rank.assign(N, 0);
    p.assign(N, 0); for (int i = 0; i < N; i++) p[i] = i; }
  int findSet(int i) { return (p[i] == i) ? i : (p[i] = findSet(p[i])); }
  bool isSameSet(int i, int j) { return findSet(i) == findSet(j); }
  void unionSet(int i, int j) {
    if (!isSameSet(i, j)) { numSets--;
    int x = findSet(i), y = findSet(j);
    // rank is used to keep the tree short
    if (rank[x] > rank[y]) { p[y] = x; setSize[x] += setSize[y]; }
    else                   { p[x] = y; setSize[y] += setSize[x];
                             if (rank[x] == rank[y]) rank[y]++; } } }
  int numDisjointSets() { return numSets; }
  int sizeOfSet(int i) { return setSize[findSet(i)]; }
};
// 4194304=4e6
const int N=5e6;
int a[N];
int n,m;
int mp[N];
int fir[N];
UnionFind uf;

void go(int x){
	int mask=0;
	REP(i,n)
		if(((1<<i)&x)==0)
			mask|=1<<i;

	for (int maskCpy = mask; ; maskCpy = (maskCpy - 1) & mask) {
		if(fir[maskCpy]!=-1){
			uf.unionSet(mp[x],fir[maskCpy]);
			break;
		}

        if(maskCpy!=x&&mp[maskCpy]!=-1){
        	uf.unionSet(mp[x],mp[maskCpy]);
        	fir[maskCpy]=uf.findSet(mp[x]);
        }
        if (maskCpy == 0) break;
    }
}

int main() {
    #ifndef ONLINE_JUDGE
    freopen("in.txt","r",stdin);
    #endif

	memset(mp,-1,sizeof mp);
    scanf("%d %d",&n,&m);
    uf.build(m);
    memset(fir,-1,sizeof fir);

    REP(i,m){
    	scanf("%d",a+i);
    	mp[a[i]]=i;
    }
	REP(i,m)go(a[i]);
	printf("%d\n", uf.numSets);
    return 0;
}


#include <bits/stdc++.h>
#include <bitset>

#define REP(i,n) for(int i=0;i<(int)n;i++)
#define REP1(i,j,n) for(int i=j;i<(int)n;i++)
#define pb(x) push_back(x)
#define fi first
#define se second
#define all(x) x.begin(),x.end()
#define double long double
#define mp(x,y) make_pair(x,y)

typedef long long ll;

using namespace std;
class UnionFind{
public:
  vector<int>p,rank,setSize;
  int numSets;
  void build(int N){
    setSize.assign(N,1);
    numSets=N;
    rank.assign(N,0);
    p.assign(N,0);
    for(int i=0;i<N;i++)p[i]=i;
  }
  int findSet(int i){return(p[i]==i)?i:(p[i]=findSet(p[i]));}
  bool isSameSet(int i,int j){return findSet(i)==findSet(j);}
  void unionSet(int i,int j){
    if(!isSameSet(i,j)){
        numSets--;
        int x=findSet(i),y=findSet(j);
        if(rank[x]>rank[y]){p[y]=x;setSize[x]+=setSize[y];}
        else{
            p[x]=y;setSize[y]+=setSize[x];
           if(rank[x]==rank[y])rank[y]++;
        }
    }
  }
  int numDisjointSets(){return numSets;}
  int sizeOfSet(int i){return setSize[findSet(i)];}
};

// 4194304=4e6
const int N=5e6;
int a[N];
int n,m;
int mp[N];
int fir[N];
UnionFind uf;
int all;
bool go(int msk,int x){
	if(msk==0)return 0;
	if(fir[msk]==-2)return 0;
	if(fir[msk]!=-1){
		uf.unionSet(mp[fir[msk]],mp[x]);
		return 1;
	}
	bool f=0;
	for(int i=0;i<n;i++)
		if(((1<<i)&msk)!=0){
			f|=go(msk^(1<<i),x);
		}

	if(mp[msk]!=-1){
		f=1;
		uf.unionSet(mp[x],mp[msk]);
	}
	if(f){
		fir[msk]=x;
	}else fir[msk]=-2;
	return f;
}

int main() {
    #ifndef ONLINE_JUDGE
    freopen("in.txt","r",stdin);
    #endif

    return 0;
}


#include <bits/stdc++.h>
#include <bitset>

#define REP(i,n) for(int i=0;i<(int)n;i++)
#define REP1(i,j,n) for(int i=j;i<(int)n;i++)
#define pb(x) push_back(x)
#define fi first
#define se second
#define all(x) x.begin(),x.end()
#define double long double
#define mp(x,y) make_pair(x,y)

typedef long long ll;

using namespace std;
class UnionFind {                                              // OOP style
public:
	vector<int> p, rank, setSize;                       // remember: vi is vector<int>
	int numSets;

public:
  void build(int N) {
    setSize.assign(N, 1); numSets = N; rank.assign(N, 0);
    p.assign(N, 0); for (int i = 0; i < N; i++) p[i] = i; }
  int findSet(int i) { return (p[i] == i) ? i : (p[i] = findSet(p[i])); }
  bool isSameSet(int i, int j) { return findSet(i) == findSet(j); }
  void unionSet(int i, int j) {
    if (!isSameSet(i, j)) { numSets--;
    int x = findSet(i), y = findSet(j);
    // rank is used to keep the tree short
    if (rank[x] > rank[y]) { p[y] = x; setSize[x] += setSize[y]; }
    else                   { p[x] = y; setSize[y] += setSize[x];
                             if (rank[x] == rank[y]) rank[y]++; } } }
  int numDisjointSets() { return numSets; }
  int sizeOfSet(int i) { return setSize[findSet(i)]; }
};
// 4194304=4e6
const int N=5e6;
int a[N];
int n,m;
int mp[N];
int fir[N];
UnionFind uf;
int all;
bool go(int msk,int x){
	if(msk==0)return 0;
	if(fir[msk]==-2)return 0;
	if(fir[msk]!=-1){
		uf.unionSet(mp[fir[msk]],mp[x]);
		return 1;
	}
	bool f=0;
	for(int i=0;i<n;i++)
		if(((1<<i)&msk)!=0){
			f|=go(msk^(1<<i),x);
		}

	if(mp[msk]!=-1)f=1;
	if(f){
		fir[msk]=x;
		uf.unionSet(mp[x],mp[msk]);
	}else fir[msk]=-2;
	return f;
}

int main() {
    #ifndef ONLINE_JUDGE
    freopen("in.txt","r",stdin);
    #endif

	memset(mp,-1,sizeof mp);
    scanf("%d %d",&n,&m);
    all=(1<<n)-1;
    uf.build(m);
    memset(fir,-1,sizeof fir);

    REP(i,m){
    	scanf("%d",a+i);
    	mp[a[i]]=i;
    	if(a[i]==0){
    		printf("1\n");
    		return 0;
    	}
    }
    // printf("asdf\n");
	REP(i,m){
		if(fir[a[i]]==-1)go(a[i]^all,a[i]);
	}
	int r=0;
	REP(i,m)r+=uf.p[i]==i;
	printf("%d\n", r);
    return 0;
}


#include <bits/stdc++.h>
#include <bitset>

#define REP(i,n) for(int i=0;i<(int)n;i++)
#define REP1(i,j,n) for(int i=j;i<(int)n;i++)
#define pb(x) push_back(x)
#define fi first
#define se second
#define all(x) x.begin(),x.end()
#define double long double
#define mp(x,y) make_pair(x,y)

typedef long long ll;

using namespace std;
class UnionFind {                                              // OOP style
public:
	vector<int> p, rank, setSize;                       // remember: vi is vector<int>
	int numSets;

public:
  void build(int N) {
    setSize.assign(N, 1); numSets = N; rank.assign(N, 0);
    p.assign(N, 0); for (int i = 0; i < N; i++) p[i] = i; }
  int findSet(int i) { return (p[i] == i) ? i : (p[i] = findSet(p[i])); }
  bool isSameSet(int i, int j) { return findSet(i) == findSet(j); }
  void unionSet(int i, int j) {
    if (!isSameSet(i, j)) { numSets--;
    int x = findSet(i), y = findSet(j);
    // rank is used to keep the tree short
    if (rank[x] > rank[y]) { p[y] = x; setSize[x] += setSize[y]; }
    else                   { p[x] = y; setSize[y] += setSize[x];
                             if (rank[x] == rank[y]) rank[y]++; } } }
  int numDisjointSets() { return numSets; }
  int sizeOfSet(int i) { return setSize[findSet(i)]; }
};
// 4194304=4e6
const int N=5e6;
int a[N];
int n,m;
int mp[N];
int fir[N];
UnionFind uf;
int all;
bool go(int msk,int x){
	if(fir[msk]!=-1){
		uf.unionSet(msk,x);
		return 1;
	}
	bool f=0;
	for(int i=0;i<n;i++)
		if(((1<<i)&msk)==1){
			f|=go(msk^(1<<i),x);
		}

	if(mp[msk]!=-1)f=1;
	if(f){
		fir[msk]=x;
		uf.unionSet(mp[x],mp[msk]);
	}
	return f;
}

int main() {
    #ifndef ONLINE_JUDGE
    freopen("in.txt","r",stdin);
    #endif

	memset(mp,-1,sizeof mp);
    scanf("%d %d",&n,&m);
    all=(1<<n)-1;
    uf.build(m);
    memset(fir,-1,sizeof fir);

    REP(i,m){
    	scanf("%d",a+i);
    	mp[a[i]]=i;
    }
    // printf("asdf\n");
	REP(i,m){
		if(fir[a[i]]==-1)go(a[i]^all,a[i]);
	}
	int r=0;
	REP(i,m)r+=uf.p[i]==i;
	printf("%d\n", r);
    return 0;
}


#include <bits/stdc++.h>
#include <bitset>

#define REP(i,n) for(int i=0;i<(int)n;i++)
#define REP1(i,j,n) for(int i=j;i<(int)n;i++)
#define pb(x) push_back(x)
#define fi first
#define se second
#define all(x) x.begin(),x.end()
#define double long double
#define mp(x,y) make_pair(x,y)

typedef long long ll;

using namespace std;
class UnionFind {                                              // OOP style
public:
	vector<int> p, rank, setSize;                       // remember: vi is vector<int>
	int numSets;

public:
  void build(int N) {
    setSize.assign(N, 1); numSets = N; rank.assign(N, 0);
    p.assign(N, 0); for (int i = 0; i < N; i++) p[i] = i; }
  int findSet(int i) { return (p[i] == i) ? i : (p[i] = findSet(p[i])); }
  bool isSameSet(int i, int j) { return findSet(i) == findSet(j); }
  void unionSet(int i, int j) {
    if (!isSameSet(i, j)) { numSets--;
    int x = findSet(i), y = findSet(j);
    // rank is used to keep the tree short
    if (rank[x] > rank[y]) { p[y] = x; setSize[x] += setSize[y]; }
    else                   { p[x] = y; setSize[y] += setSize[x];
                             if (rank[x] == rank[y]) rank[y]++; } } }
  int numDisjointSets() { return numSets; }
  int sizeOfSet(int i) { return setSize[findSet(i)]; }
};
// 4194304=4e6
const int N=5e6;
int a[N];
int n,m;
int mp[N];
int fir[N];
UnionFind uf;
int all;
bool go(int msk,int x){
	if(fir[msk]==-2)return 0;
	if(fir[msk]!=-1){
		uf.unionSet(mp[msk],mp[x]);
		return 1;
	}
	bool f=0;
	for(int i=0;i<n;i++)
		if(((1<<i)&msk)!=0){
			f|=go(msk^(1<<i),x);
		}

	if(mp[msk]!=-1)f=1;
	if(f){
		fir[msk]=x;
		uf.unionSet(mp[x],mp[msk]);
	}else fir[msk]=-2;
	return f;
}

int main() {
    #ifndef ONLINE_JUDGE
    freopen("in.txt","r",stdin);
    #endif

	memset(mp,-1,sizeof mp);
    scanf("%d %d",&n,&m);
    all=(1<<n)-1;
    uf.build(m);
    memset(fir,-1,sizeof fir);

    REP(i,m){
    	scanf("%d",a+i);
    	mp[a[i]]=i;
    }
    // printf("asdf\n");
	REP(i,m){
		if(fir[a[i]]==-1)go(a[i]^all,a[i]);
	}
	int r=0;
	REP(i,m)r+=uf.p[i]==i;
	printf("%d\n", r);
    return 0;
}


#pragma GCC target ("avx2")
#pragma GCC optimize ("O3")
#pragma GCC optimize ("unroll-loops")
#include <bits/stdc++.h>
using namespace std;
template<class T, class S>
ostream& operator << (ostream &o, const pair<T, S> &p) {
    return o << '(' << p.first << ", " << p.second << ')';
}
template<template<class, class...> class T, class... A>
typename enable_if<!is_same<T<A...>, string>(), ostream&>::type
operator << (ostream &o, T<A...> V) {
	o << '[';
	for(auto a : V) o << a << ", ";
	return o << ']';
}

typedef int ll;
typedef long double ld;
typedef pair<ll, ll> pl;

#define G(x) ll x; cin >> x;
#define GD(x) ld x; cin >> x;
#define GS(s) string s; cin >> s;
#define F(i, l, r) for(ll i = l; i < (r); i++)
#define FD(i, r, l) for(ll i = r; i > (l); i--)
#define P(a, n) { cout << "{ "; F(_, 0, n) cout << a[_] << " "; cout << "}\n"; }
#define EX(x) { cout << x << '\n'; exit(0); }
#define A(a) (a).begin(), (a).end()
#define K first
#define V second
#define M 1000000007 //998244353
#define N 4200000
#define L 23

ll n, m, k, a[N];
bool done[N][L], used[N], ina[N];

ll bit_select(ll mask, ll c) {
    for(ll j = 0;; ++j) {
        if(mask & (1 << j)) c--;
        if(c < 0) return j;
    }
}

void dfs(ll mask, ll fix = 0) {
    if(done[mask][fix]) return;
    done[mask][fix] = true;
    if(ina[mask]) dfs(k - mask), used[mask] = true;
    if(fix == __builtin_popcount(mask)) return;
    ll j = bit_select(mask, fix);
    dfs(mask ^ (1 << j), fix);
    dfs(mask, fix + 1);
}

int main() {
    ios_base::sync_with_stdio(0);
    cin.tie(0);
    cin >> n >> m; k = (1 << n) - 1;
    F(i, 0, m) cin >> a[i], ina[a[i]] = true;
    ll ans = 0;
    F(i, 0, m) if(!used[a[i]]) dfs(k - a[i]), used[a[i]] = true, ans++;
    cout << ans << '\n';
}


#pragma GCC target ("avx2")
#pragma GCC optimize ("O3")
#pragma GCC optimize ("unroll-loops")
#include <bits/stdc++.h>
using namespace std;
template<class T, class S>
ostream& operator << (ostream &o, const pair<T, S> &p) {
    return o << '(' << p.first << ", " << p.second << ')';
}
template<template<class, class...> class T, class... A>
typename enable_if<!is_same<T<A...>, string>(), ostream&>::type
operator << (ostream &o, T<A...> V) {
	o << '[';
	for(auto a : V) o << a << ", ";
	return o << ']';
}

typedef int ll;
typedef long double ld;
typedef pair<ll, ll> pl;

#define G(x) ll x; cin >> x;
#define GD(x) ld x; cin >> x;
#define GS(s) string s; cin >> s;
#define F(i, l, r) for(ll i = l; i < (r); i++)
#define FD(i, r, l) for(ll i = r; i > (l); i--)
#define P(a, n) { cout << "{ "; F(_, 0, n) cout << a[_] << " "; cout << "}\n"; }
#define EX(x) { cout << x << '\n'; exit(0); }
#define A(a) (a).begin(), (a).end()
#define K first
#define V second
#define M 1000000007 //998244353
#define N 4200000
#define L 23

ll n, m, k, a[N], done[N];
bool used[N], ina[N];

ll bit_select(ll mask, ll c) {
    for(ll j = 1;; j *= 2) {
        if(mask & j) c--;
        if(c < 0) return j;
    }
}

void dfs(ll mask, ll fix = 0) {
    if(done[mask] & (1 << fix)) return;
    done[mask] |= (1 << fix);
    if(ina[mask]) used[mask] = true, dfs(k - mask);
    if(fix == __builtin_popcount(mask)) return;
    dfs(mask ^ bit_select(mask, fix), fix);
    dfs(mask, fix + 1);
}

int main() {
    ios_base::sync_with_stdio(0);
    cin.tie(0);
    cin >> n >> m; k = (1 << n) - 1;
    F(i, 0, m) cin >> a[i], ina[a[i]] = true;
    ll ans = 0;
    F(i, 0, m) if(!used[a[i]]) dfs(k - a[i]), used[a[i]] = true, ans++;
    cout << ans << '\n';
}


#pragma GCC target ("avx2")
#pragma GCC optimize ("O3")
#pragma GCC optimize ("unroll-loops")
#include <bits/stdc++.h>
using namespace std;
template<class T, class S>
ostream& operator << (ostream &o, const pair<T, S> &p) {
    return o << '(' << p.first << ", " << p.second << ')';
}
template<template<class, class...> class T, class... A>
typename enable_if<!is_same<T<A...>, string>(), ostream&>::type
operator << (ostream &o, T<A...> V) {
	o << '[';
	for(auto a : V) o << a << ", ";
	return o << ']';
}

typedef int ll;
typedef long double ld;
typedef pair<ll, ll> pl;

#define G(x) ll x; cin >> x;
#define GD(x) ld x; cin >> x;
#define GS(s) string s; cin >> s;
#define F(i, l, r) for(ll i = l; i < (r); i++)
#define FD(i, r, l) for(ll i = r; i > (l); i--)
#define P(a, n) { cout << "{ "; F(_, 0, n) cout << a[_] << " "; cout << "}\n"; }
#define EX(x) { cout << x << '\n'; exit(0); }
#define A(a) (a).begin(), (a).end()
#define K first
#define V second
#define M 1000000007 //998244353
#define N 4200000
#define L 23

ll n, m, a[N];
bool done[N][L], used[N], ina[N];

ll bit_select(ll mask, ll c) {
    for(ll j = 0;; ++j) {
        if(mask & (1 << j)) c--;
        if(c < 0) return j;
    }
}

void doshit(ll x);

void dfs(ll mask, ll fix) {
    if(done[mask][fix]) return;
    done[mask][fix] = true;
    if(ina[mask]) doshit(mask);
    if(fix == __builtin_popcount(mask)) return;
    ll j = bit_select(mask, fix);
    dfs(mask ^ (1 << j), fix);
    dfs(mask, fix + 1);
}

void doshit(ll x) {
    dfs((1 << n) - 1 - x, 0);
    used[x] = true;
}

int main() {
    ios_base::sync_with_stdio(0);
    cin.tie(0);
    cin >> n >> m;
    F(i, 0, m) cin >> a[i], ina[a[i]] = true;
    ll ans = 0;
    F(i, 0, m) if(!used[a[i]]) doshit(a[i]), ans++;
    cout << ans << '\n';
}


#pragma GCC target ("avx2")
#pragma GCC optimize ("O3")
#pragma GCC optimize ("unroll-loops")
#include <bits/stdc++.h>
using namespace std;
template<class T, class S>
ostream& operator << (ostream &o, const pair<T, S> &p) {
    return o << '(' << p.first << ", " << p.second << ')';
}
template<template<class, class...> class T, class... A>
typename enable_if<!is_same<T<A...>, string>(), ostream&>::type
operator << (ostream &o, T<A...> V) {
	o << '[';
	for(auto a : V) o << a << ", ";
	return o << ']';
}

typedef long long int ll;
typedef long double ld;
typedef pair<ll, ll> pl;

#define G(x) ll x; cin >> x;
#define GD(x) ld x; cin >> x;
#define GS(s) string s; cin >> s;
#define F(i, l, r) for(ll i = l; i < (r); i++)
#define FD(i, r, l) for(ll i = r; i > (l); i--)
#define P(a, n) { cout << "{ "; F(_, 0, n) cout << a[_] << " "; cout << "}\n"; }
#define EX(x) { cout << x << '\n'; exit(0); }
#define A(a) (a).begin(), (a).end()
#define K first
#define V second
#define M 1000000007 //998244353
#define N 5000010
#define L 25

ll n, m, a[N];
bool done[N][L], used[N], ina[N];

ll bit_select(ll mask, ll c) {
    ll j = -1;
    while(~++j) {
        if(mask & (1 << j)) c--;
        if(c < 0) return j;
    }
}

void doshit(ll x);

void dfs(ll mask, ll fix) {
    if(done[mask][fix]) return;
    done[mask][fix] = true;
    if(ina[mask]) doshit(mask);
    if(fix == __builtin_popcount(mask)) return;
    ll j = bit_select(mask, fix);
    dfs(mask ^ (1 << j), fix);
    dfs(mask, fix + 1);
}

void doshit(ll x) {
    dfs((1 << n) - 1 - x, 0);
    used[x] = true;
}

int main() {
    ios_base::sync_with_stdio(0);
    cin.tie(0);
    cin >> n >> m;
    F(i, 0, m) cin >> a[i], ina[a[i]] = true;
    ll ans = 0;
    F(i, 0, m) if(!used[a[i]]) doshit(a[i]), ans++;
    cout << ans << '\n';
}


#include<bits/stdc++.h>
using namespace std;

int nodes[4194399];
int visited[4194399];
int n, m, components;
void create(int x, int depth, int created);
void dfs(int x)
{
    if(visited[x] && nodes[x]!=1) return;
    visited[x] = 1;
    create(x,0,0);
}

void create(int x, int depth, int created)
{
    if(depth == n)
    {
        if(!visited[created] && nodes[created])dfs(created);
        //cout << x << "  "<< created << "  "<< depth <<endl;
        return;
    }
    create(x,depth+1, created);
    if((x&(1<<depth)) == 0)create(x,depth+1, created+(1<<depth));
}

int main()
{
    scanf("%d %d", &n, &m);
    for(int i=0; i<m; i++)
    {
        int a;
        cin >> a;
        nodes[a] =1;
    }

    for(int i=0; i<(1<<n); i++)
    {
        if(!visited[i] && nodes[i])
        {
            components++;
            //cout << "here " << i <<endl;
            dfs(i);
        }
    }
    printf("%d", components);
    return 0;
}


#include<bits/stdc++.h>
using namespace std;

int nodes[4194399];
int visited[4194399];
int n, m, components;
void create(int x, int depth, int created);
void dfs(int x)
{
    if(visited[x] && nodes[x]!=1) return;
    visited[x] = 1;
    create(x,0,0);
}

void create(int x, int depth, int created)
{
    if(depth == n)
    {
        if(!visited[created] && nodes[created])dfs(created);
        //cout << x << "  "<< created << "  "<< depth <<endl;
        return;
    }
    create(x,depth+1, created);
    if((x&(1<<depth)) == 0)create(x,depth+1, created+(1<<depth));
}

int main()
{
    scanf("%d %d", &n, &m);
    vector<int> copied;
    for(int i=0; i<m; i++)
    {
        int a;
        cin >> a;
        nodes[a] =1;
        copied.push_back(a);
    }

    for(int i=0; i<copied.size(); i++)
    {
        if(!visited[copied[i]])
        {
            components++;
            //cout << "here " << i <<endl;
            dfs(copied[i]);
        }
    }
    printf("%d", components);
    return 0;
}


/*
    Washief Hossain Mugdho
    11 October 2020
    Codeforces 485C
*/

#ifndef DEBUG
#pragma GCC optimize("O3")
#endif

#include <bits/stdc++.h>
#define ull unsigned long long
#define ll long long
#define pb push_back
#define mp make_pair
#define fr first
#define sc second
#define fastio ios_base::sync_with_stdio(0)
#define untie cin.tie(0)
#define ms(a, b) memset(a, b, sizeof a)
using namespace std;
int n, m, b;
unordered_set<int> numsHash;
bool visited[1 << 22];

inline int complement(int x)
{
    return (((1LL << n) - 1) - x);
}

void dfs(int a)
{
    for (int i = 0; i < n; i++)
        if ((a & (1 << i)) && !visited[a - (1 << i)])
        {
            visited[a - (1 << i)] = 1;
            dfs(a - (1 << i));
        }

    if (numsHash.find(a) != numsHash.end() && !visited[complement(a)])
    {
        visited[complement(a)] = 1;
        dfs(complement(a));
    }
}

int main()
{
#ifdef LOCAL_OUTPUT
    freopen(LOCAL_OUTPUT, "w", stdout);
#endif
#ifdef LOCAL_INPUT
    freopen(LOCAL_INPUT, "r", stdin);
#endif
    fastio;
    untie;
    cin >> n >> m;
    for (int i = 0; i < m; i++)
    {
        cin >> b;
        numsHash.insert(b);
    }
    int components = 0;
    for (auto x : numsHash)
        if (!visited[x])
        {
            components++;
            visited[complement(x)] = 1;
            dfs(complement(x));
        }

    cout << components << endl;
}


/*
    Washief Hossain Mugdho
    11 October 2020
    Codeforces 485C
*/

#ifndef DEBUG
#pragma GCC optimize("O3")
#endif

#include <bits/stdc++.h>
#define ull unsigned long long
#define ll long long
#define pb push_back
#define mp make_pair
#define fr first
#define sc second
#define fastio ios_base::sync_with_stdio(0)
#define untie cin.tie(0)
#define ms(a, b) memset(a, b, sizeof a)
using namespace std;
int n, m, a;
unordered_set<int> numsHash;
bool visited[1 << 23];

void dfs(int a)
{
    for (int i = 0; i < n; i++)
        if (a & (1 << i) && !visited[a & (~(1 << i))])
        {
            visited[a & (~(1 << i))] = 1;
            dfs(a & (~(1 << i)));
        }

    if (numsHash.find(a) != numsHash.end() && !visited[((1 << n) - 1) & (~a)])
    {
        visited[((1 << n) - 1) & (~a)] = 1;
        dfs(((1 << n) - 1) & (~a));
    }
}

int main()
{
#ifdef LOCAL_OUTPUT
    freopen(LOCAL_OUTPUT, "w", stdout);
#endif
#ifdef LOCAL_INPUT
    freopen(LOCAL_INPUT, "r", stdin);
#endif
    cin >> n >> m;
    for (int i = 0; i < m; i++)
    {
        cin >> a;
        numsHash.insert(a);
    }
    int components = 0;
    for (auto x : numsHash)
        if (!visited[x])
        {
            components++;
            visited[x] = 1;
            visited[((1 << n) - 1) & (~x)] = 1;
            dfs(((1 << n) - 1) & (~x));
        }

    cout << components << endl;
}


/*
    Washief Hossain Mugdho
    11 October 2020
    Codeforces 485C
*/

#ifndef DEBUG
#pragma GCC optimize("O3")
#endif

#include <bits/stdc++.h>
#define ull unsigned long long
#define ll long long
#define pb push_back
#define mp make_pair
#define fr first
#define sc second
#define fastio ios_base::sync_with_stdio(0)
#define untie cin.tie(0)
#define ms(a, b) memset(a, b, sizeof a)
using namespace std;
int n, m, a;
unordered_map<int, bool> numsHash;

void dfs(int a)
{
    int complememt = ((1 << n) - 1) & (~a);
    for (int mask = complememt; mask; mask = (mask - 1) & complememt)
        if (numsHash.find(mask) != numsHash.end() && numsHash[mask] == 0)
        {
            numsHash[mask] = 1;
            dfs(mask);
        }

    if (numsHash.find(0) != numsHash.end() && numsHash[0] == 0)
    {
        numsHash[0] = 1;
        dfs(0);
    }
}

int main()
{
#ifdef LOCAL_OUTPUT
    freopen(LOCAL_OUTPUT, "w", stdout);
#endif
#ifdef LOCAL_INPUT
    freopen(LOCAL_INPUT, "r", stdin);
#endif
    cin >> n >> m;
    for (int i = 0; i < m; i++)
    {
        cin >> a;
        numsHash.insert({a, 0});
    }
    int components = 0;
    for (auto x : numsHash)
        if (!x.sc)
        {
            components++;
            dfs(x.fr);
        }

    cout << components << endl;
}


/*
    Washief Hossain Mugdho
    11 October 2020
    Codeforces 485C
*/

#ifndef DEBUG
#pragma GCC optimize("O3")
#endif

#include <bits/stdc++.h>
#define ull unsigned long long
#define ll long long
#define pb push_back
#define mp make_pair
#define fr first
#define sc second
#define fastio ios_base::sync_with_stdio(0)
#define untie cin.tie(0)
#define ms(a, b) memset(a, b, sizeof a)
using namespace std;
int n, m, a;
unordered_map<int, bool> numsHash;

void dfs(int a)
{
    int complememt = ((1 << n) - 1) & (~a);
    for (int mask = complememt; mask; mask = (mask - 1) & complememt)
        if (numsHash.find(mask) != numsHash.end() && numsHash[mask] == 0)
        {
            numsHash[mask] = 1;
            dfs(mask);
        }
}

int main()
{
#ifdef LOCAL_OUTPUT
    freopen(LOCAL_OUTPUT, "w", stdout);
#endif
#ifdef LOCAL_INPUT
    freopen(LOCAL_INPUT, "r", stdin);
#endif
    cin >> n >> m;
    for (int i = 0; i < m; i++)
    {
        cin >> a;
        numsHash.insert({a, 0});
    }
    int components = 0;
    for (auto x : numsHash)
        if (!x.sc)
        {
            components++;
            dfs(x.fr);
        }

    cout << components << endl;
}


#include<iostream>
#include<string>
#include<cstdio>
#include<vector>
#include<cmath>
#include<algorithm>
#include<functional>
#include<iomanip>
#include<queue>
#include<ciso646>
#include<random>
#include<map>
#include<set>
#include<bitset>
#include<stack>
#include<unordered_map>
#include<utility>
#include<cassert>
#include<complex>
#include<numeric>
using namespace std;

//#define int long long
typedef long long ll;

typedef unsigned long long ul;
typedef unsigned int ui;
constexpr ll mod = 1000000007;
const ll INF = mod * mod;
typedef pair<int, int>P;
#define stop char nyaa;cin>>nyaa;
#define rep(i,n) for(int i=0;i<n;i++)
#define per(i,n) for(int i=n-1;i>=0;i--)
#define Rep(i,sta,n) for(int i=sta;i<n;i++)
#define rep1(i,n) for(int i=1;i<=n;i++)
#define per1(i,n) for(int i=n;i>=1;i--)
#define Rep1(i,sta,n) for(int i=sta;i<=n;i++)
#define all(v) (v).begin(),(v).end()
typedef pair<ll, ll> LP;
typedef long double ld;
typedef pair<ld, ld> LDP;
const ld eps = 1e-12;
const ld pi = acos(-1.0);

ll mod_pow(ll x, ll n, ll m) {
	ll res = 1;
	while (n) {
		if (n & 1)res = res * x % m;
		x = x * x % m; n >>= 1;
	}
	return res;
}
struct modint {
	ll n;
	modint() :n(0) { ; }
	modint(ll m) :n(m) {
		if (n >= mod)n %= mod;
		else if (n < 0)n = (n % mod + mod) % mod;
	}
	operator int() { return n; }
};
bool operator==(modint a, modint b) { return a.n == b.n; }
modint operator+=(modint& a, modint b) { a.n += b.n; if (a.n >= mod)a.n -= mod; return a; }
modint operator-=(modint& a, modint b) { a.n -= b.n; if (a.n < 0)a.n += mod; return a; }
modint operator*=(modint& a, modint b) { a.n = ((ll)a.n * b.n) % mod; return a; }
modint operator+(modint a, modint b) { return a += b; }
modint operator-(modint a, modint b) { return a -= b; }
modint operator*(modint a, modint b) { return a *= b; }
modint operator^(modint a, int n) {
	if (n == 0)return modint(1);
	modint res = (a * a) ^ (n / 2);
	if (n % 2)res = res * a;
	return res;
}

ll inv(ll a, ll p) {
	return (a == 1 ? 1 : (1 - p * inv(p % a, a)) / a + p);
}
modint operator/(modint a, modint b) { return a * modint(inv(b, mod)); }

const int max_n = 1 << 20;
modint fact[max_n], factinv[max_n];
void init_f() {
	fact[0] = modint(1);
	for (int i = 0; i < max_n - 1; i++) {
		fact[i + 1] = fact[i] * modint(i + 1);
	}
	factinv[max_n - 1] = modint(1) / fact[max_n - 1];
	for (int i = max_n - 2; i >= 0; i--) {
		factinv[i] = factinv[i + 1] * modint(i + 1);
	}
}
modint comb(int a, int b) {
	if (a < 0 || b < 0 || a < b)return 0;
	return fact[a] * factinv[b] * factinv[a - b];
}
int dx[4] = { 1,0,-1,0 };
int dy[4] = { 0,1,0,-1 };

const int MAX_V = 1<<22;
int n;
int V;
vector<int>G[MAX_V];
vector<int>rG[MAX_V];
vector<int>vs;
bool used[MAX_V];
int cmp[MAX_V];
void add_edge(int from, int to) {
	G[from].push_back(to);
	rG[to].push_back(from);
}
void dfs(int v) {
	used[v] = true;
	rep(i, (int)G[v].size()) {
		if (!used[G[v][i]])dfs(G[v][i]);
	}
	rep(j, n)if (v & (1 << j)) {
		if (!used[v ^ (1 << j)])dfs(v ^ (1 << j));
	}
	vs.push_back(v);
}
void rdfs(int v, int k) {
	used[v] = true;
	cmp[v] = k;
	rep(i, (int)rG[v].size()) {
		if (!used[rG[v][i]])rdfs(rG[v][i], k);
	}
	rep(j, n) {
		if ((v & (1 << j)) == 0) {
			if (!used[v ^ (1 << j)])rdfs(v^(1<<j), k);
		}
	}
}
int scc() {
	fill(used, used + V, false);
	vs.clear();
	rep(v, V) {
		if (!used[v])dfs(v);
	}
	fill(used, used + V, false);
	int k = 0;
	per(i, (int)vs.size()) {
		if (!used[vs[i]])rdfs(vs[i], k ++);
	}
	return k;
}
void solve() {
	int m; cin >> n >> m;
	vector<int> a(m);
	rep(i, m) {
		cin >> a[i];
	}
	/*rep(i, (1 << n)) {
		rep(j, n)if (i & (1 << j)) {
			int to = i ^ (1 << j);
			add_edge(i, to);
		}
	}*/
	rep(i, m) {
		add_edge(a[i], (1 << n) - 1 - a[i]);
	}
	V = (1 << n);
	scc();
	vector<bool> exi(1 << n);
	rep(i, m) {
		//cout << i << " " << cmp[i] << "\n";
		exi[cmp[a[i]]] = true;
	}

	int ans = 0;
	rep(i, 1 << n)if (exi[i])ans++;
	cout << ans << "\n";
}

signed main() {
	ios::sync_with_stdio(false);
	cin.tie(0);
	//cout << fixed << setprecision(10);
	//init_f();
//	int t; cin >> t; rep(i, t)
	solve();
	return 0;
}


#include<iostream>
#include<string>
#include<cstdio>
#include<vector>
#include<cmath>
#include<algorithm>
#include<functional>
#include<iomanip>
#include<queue>
#include<ciso646>
#include<random>
#include<map>
#include<set>
#include<bitset>
#include<stack>
#include<unordered_map>
#include<utility>
#include<cassert>
#include<complex>
#include<numeric>
using namespace std;

//#define int long long
typedef long long ll;

typedef unsigned long long ul;
typedef unsigned int ui;
constexpr ll mod = 1000000007;
const ll INF = mod * mod;
typedef pair<int, int>P;
#define stop char nyaa;cin>>nyaa;
#define rep(i,n) for(int i=0;i<n;i++)
#define per(i,n) for(int i=n-1;i>=0;i--)
#define Rep(i,sta,n) for(int i=sta;i<n;i++)
#define rep1(i,n) for(int i=1;i<=n;i++)
#define per1(i,n) for(int i=n;i>=1;i--)
#define Rep1(i,sta,n) for(int i=sta;i<=n;i++)
#define all(v) (v).begin(),(v).end()
typedef pair<ll, ll> LP;
typedef long double ld;
typedef pair<ld, ld> LDP;
const ld eps = 1e-12;
const ld pi = acos(-1.0);

ll mod_pow(ll x, ll n, ll m) {
	ll res = 1;
	while (n) {
		if (n & 1)res = res * x % m;
		x = x * x % m; n >>= 1;
	}
	return res;
}
struct modint {
	ll n;
	modint() :n(0) { ; }
	modint(ll m) :n(m) {
		if (n >= mod)n %= mod;
		else if (n < 0)n = (n % mod + mod) % mod;
	}
	operator int() { return n; }
};
bool operator==(modint a, modint b) { return a.n == b.n; }
modint operator+=(modint& a, modint b) { a.n += b.n; if (a.n >= mod)a.n -= mod; return a; }
modint operator-=(modint& a, modint b) { a.n -= b.n; if (a.n < 0)a.n += mod; return a; }
modint operator*=(modint& a, modint b) { a.n = ((ll)a.n * b.n) % mod; return a; }
modint operator+(modint a, modint b) { return a += b; }
modint operator-(modint a, modint b) { return a -= b; }
modint operator*(modint a, modint b) { return a *= b; }
modint operator^(modint a, int n) {
	if (n == 0)return modint(1);
	modint res = (a * a) ^ (n / 2);
	if (n % 2)res = res * a;
	return res;
}

ll inv(ll a, ll p) {
	return (a == 1 ? 1 : (1 - p * inv(p % a, a)) / a + p);
}
modint operator/(modint a, modint b) { return a * modint(inv(b, mod)); }

const int max_n = 1 << 20;
modint fact[max_n], factinv[max_n];
void init_f() {
	fact[0] = modint(1);
	for (int i = 0; i < max_n - 1; i++) {
		fact[i + 1] = fact[i] * modint(i + 1);
	}
	factinv[max_n - 1] = modint(1) / fact[max_n - 1];
	for (int i = max_n - 2; i >= 0; i--) {
		factinv[i] = factinv[i + 1] * modint(i + 1);
	}
}
modint comb(int a, int b) {
	if (a < 0 || b < 0 || a < b)return 0;
	return fact[a] * factinv[b] * factinv[a - b];
}
int dx[4] = { 1,0,-1,0 };
int dy[4] = { 0,1,0,-1 };

struct graph {
private:
	int n;
	vector<vector<int>> G, rG;
	vector<bool> used;
	vector<int> vs;

	int mk;
	vector<vector<int>> fG;
	vector<vector<int>> ori;
	vector<int> trans;
public:
	graph(int sz) {
		n = sz;
		G.resize(n);
		rG.resize(n);
		used.resize(n);

		fG.resize(n);
		trans.resize(n, -1);
		ori.resize(n);
	}
	void add_edge(int a, int b) {
		G[a].push_back(b);
		rG[b].push_back(a);
	}
	void dfs(int v) {
		used[v] = true;
		rep(i, G[v].size()) {
			if (!used[G[v][i]])dfs(G[v][i]);
		}
		vs.push_back(v);
	}
	void rdfs(int v, int k) {
		used[v] = true;
		queue<int> q; q.push(v);
		vector<int> c;
		while (!q.empty()) {
			int id = q.front(); q.pop();
			ori[k].push_back(id);
			rep(j, rG[id].size()) {
				int to = rG[id][j];
				if (used[to]) {
					if (trans[to] >= 0)c.push_back(trans[to]);
					continue;
				}
				used[to] = true; q.push(to);
			}
		}
		sort(c.begin(), c.end());
		int len = unique(c.begin(), c.end()) - c.begin();
		rep(i, len) {
			fG[c[i]].push_back(k);
		}
		rep(i, ori[k].size()) {
			trans[ori[k][i]] = k;
		}
	}
	void scc() {
		fill(used.begin(), used.end(), false);
		rep(i, n) {
			if (!used[i])dfs(i);
		}
		fill(used.begin(), used.end(), false);
		int k = 0;
		per(i, (int)vs.size()) {
			if (!used[vs[i]]) {
				rdfs(vs[i], k); k++;
			}
		}
		mk = k;
	}
	int query(vector<bool>& b) {
		int res = 0;
		rep(i, mk) {
			bool exi = false;
			for (int id : ori[i]) {
				if (b[id])exi = true;
			}
			if (exi)res++;
		}
		return res;
	}
};
void solve() {
	int n, m; cin >> n >> m;
	vector<int> a(m);
	rep(i, m) {
		cin >> a[i];
	}
	graph g(1 << n);
	rep(i, (1 << n)) {
		rep(j, n)if (i & (1 << j)) {
			int to = i ^ (1 << j);
			g.add_edge(i, to);
		}
	}
	rep(i, m) {
		g.add_edge(a[i], (1 << n) - 1 - a[i]);
	}
	g.scc();
	vector<bool> exi(1 << n);
	rep(i, m)exi[a[i]] = true;
	int ans = g.query(exi);
	cout << ans << "\n";
}

signed main() {
	ios::sync_with_stdio(false);
	cin.tie(0);
	//cout << fixed << setprecision(10);
	//init_f();
//	int t; cin >> t; rep(i, t)
	solve();
	return 0;
}


#include<iostream>
#include<string>
#include<cstdio>
#include<vector>
#include<cmath>
#include<algorithm>
#include<functional>
#include<iomanip>
#include<queue>
#include<ciso646>
#include<random>
#include<map>
#include<set>
#include<bitset>
#include<stack>
#include<unordered_map>
#include<utility>
#include<cassert>
#include<complex>
#include<numeric>
using namespace std;

//#define int long long
typedef long long ll;

typedef unsigned long long ul;
typedef unsigned int ui;
constexpr ll mod = 1000000007;
const ll INF = mod * mod;
typedef pair<int, int>P;
#define stop char nyaa;cin>>nyaa;
#define rep(i,n) for(int i=0;i<n;i++)
#define per(i,n) for(int i=n-1;i>=0;i--)
#define Rep(i,sta,n) for(int i=sta;i<n;i++)
#define rep1(i,n) for(int i=1;i<=n;i++)
#define per1(i,n) for(int i=n;i>=1;i--)
#define Rep1(i,sta,n) for(int i=sta;i<=n;i++)
#define all(v) (v).begin(),(v).end()
typedef pair<ll, ll> LP;
typedef long double ld;
typedef pair<ld, ld> LDP;
const ld eps = 1e-12;
const ld pi = acos(-1.0);

ll mod_pow(ll x, ll n, ll m) {
	ll res = 1;
	while (n) {
		if (n & 1)res = res * x % m;
		x = x * x % m; n >>= 1;
	}
	return res;
}
struct modint {
	ll n;
	modint() :n(0) { ; }
	modint(ll m) :n(m) {
		if (n >= mod)n %= mod;
		else if (n < 0)n = (n % mod + mod) % mod;
	}
	operator int() { return n; }
};
bool operator==(modint a, modint b) { return a.n == b.n; }
modint operator+=(modint& a, modint b) { a.n += b.n; if (a.n >= mod)a.n -= mod; return a; }
modint operator-=(modint& a, modint b) { a.n -= b.n; if (a.n < 0)a.n += mod; return a; }
modint operator*=(modint& a, modint b) { a.n = ((ll)a.n * b.n) % mod; return a; }
modint operator+(modint a, modint b) { return a += b; }
modint operator-(modint a, modint b) { return a -= b; }
modint operator*(modint a, modint b) { return a *= b; }
modint operator^(modint a, int n) {
	if (n == 0)return modint(1);
	modint res = (a * a) ^ (n / 2);
	if (n % 2)res = res * a;
	return res;
}

ll inv(ll a, ll p) {
	return (a == 1 ? 1 : (1 - p * inv(p % a, a)) / a + p);
}
modint operator/(modint a, modint b) { return a * modint(inv(b, mod)); }

const int max_n = 1 << 20;
modint fact[max_n], factinv[max_n];
void init_f() {
	fact[0] = modint(1);
	for (int i = 0; i < max_n - 1; i++) {
		fact[i + 1] = fact[i] * modint(i + 1);
	}
	factinv[max_n - 1] = modint(1) / fact[max_n - 1];
	for (int i = max_n - 2; i >= 0; i--) {
		factinv[i] = factinv[i + 1] * modint(i + 1);
	}
}
modint comb(int a, int b) {
	if (a < 0 || b < 0 || a < b)return 0;
	return fact[a] * factinv[b] * factinv[a - b];
}
int dx[4] = { 1,0,-1,0 };
int dy[4] = { 0,1,0,-1 };

const int MAX_V = 1<<22;
int n;
int V;
vector<int>vs;
bool used[MAX_V];
int cmp[MAX_V];

bool exi[MAX_V];
void dfs(int v) {
	used[v] = true;
	if (exi[v]) {
		if (!used[V - 1 - v])dfs(V - 1 - v);
	}
	rep(j, n)if (v & (1 << j)) {
		if (!used[v ^ (1 << j)])dfs(v ^ (1 << j));
	}
	vs.push_back(v);
}
void rdfs(int v, int k) {
	used[v] = true;
	cmp[v] = k;
	if (exi[V - 1 - v]) {
		if (!used[V - 1 - v])rdfs(V - 1 - v, k);
	}
	rep(j, n) {
		if ((v & (1 << j)) == 0) {
			if (!used[v ^ (1 << j)])rdfs(v^(1<<j), k);
		}
	}
}
int scc() {
	fill(used, used + V, false);
	vs.clear();
	rep(v, V) {
		if (!used[v])dfs(v);
	}
	fill(used, used + V, false);
	int k = 0;
	per(i, (int)vs.size()) {
		if (!used[vs[i]])rdfs(vs[i], k ++);
	}
	return k;
}
void solve() {
	int m; cin >> n >> m;
	vector<int> a(m);
	rep(i, m) {
		cin >> a[i];
		exi[a[i]] = true;
	}
	/*rep(i, (1 << n)) {
		rep(j, n)if (i & (1 << j)) {
			int to = i ^ (1 << j);
			add_edge(i, to);
		}
	}*/
	V = (1 << n);
	scc();
	vector<bool> b(1 << n);
	rep(i, m) {
		//cout << i << " " << cmp[i] << "\n";
		b[cmp[a[i]]] = true;
	}

	int ans = 0;
	rep(i, 1 << n)if (b[i])ans++;
	cout << ans << "\n";
}

signed main() {
	ios::sync_with_stdio(false);
	cin.tie(0);
	//cout << fixed << setprecision(10);
	//init_f();
//	int t; cin >> t; rep(i, t)
	solve();
	return 0;
}


#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <iostream>
#include <vector>
#include <algorithm>
#include <cmath>
#include <set>
#include <map>
#include <unordered_map>
#include <tuple>
#include <functional>
#include <string>
#include <stack>
#include <string.h>
#include <queue>
#include <numeric>
#include <climits>
#include <array>
#include <bitset>
#include <iomanip>

using namespace std;

using ll = long long;
using ull = unsigned long long;
const int K = 22;
const int N = (1 << K) + 10;
const int M = 1e5 + 10;
const int SN = 1000;
const int LG = 21;
const ll mod = 998244353;

using namespace std;

int arr[N];
int used[N];
int res[N];
int sv[N];
int chck[N];
int tcnt[N];

int dsu[N];

int get_set(int v) {
    if (dsu[v] == v) return v;
    return dsu[v] = get_set(dsu[v]);
}
int cnt = 0;

int merge_sets(int a, int b) {
    a = get_set(a);
    b = get_set(b);
    if (a == b) return a;
    cnt--;
    if (rand() % 2) {
        swap(a, b);
    }
    return dsu[b] = a;
}

bool is_null = false;

int solve() {
    int n, m;
    scanf("%d%d", &n, &m);
    int nwm = m;
    for (int i = 0; i < N; ++i) {
        res[i] = sv[i] = -1;
    }
    for (int i = 1; i <= m; ++i) {
        scanf("%d", arr + i);
        tcnt[arr[i]]++;
        if (!used[arr[i]]) cnt++;
        is_null = !arr[i];
        used[arr[i]] = 1;
        dsu[arr[i]] = arr[i];
        sv[arr[i]] = arr[i];
    }

    //if (is_null)return printf("1"), 0;
    int tmp;
    for (int mask = 0; mask < N; ++mask) {
        if (!used[mask]) continue;
        for (int bit = 1 << n - 1; bit; bit >>= 1) {
            if (mask & bit) continue;
            tmp = mask | bit;
            used[tmp] = 1;
            if (sv[tmp] == -1) sv[tmp] = sv[mask];
        }
    }
    int b = (1 << n) - 1;
    for (int i = 1; i <= m; ++i) {
        int inv = ~arr[i] & b;
        if (chck[arr[i]]) continue;
        if (!used[inv]) {
            cnt+= tcnt[arr[i]]-1;
            chck[arr[i]] = 1;
            continue;
        }
        if (res[inv]!=-1) res[inv] = merge_sets(arr[i], res[inv]);
        else res[inv] = get_set(arr[i]);

    }
    for (int mask = (1 << n) - 1; mask; --mask) {
        if (!used[mask]) continue;
        if (res[mask] == -1) continue;
        if (sv[mask] != -1) res[mask] = merge_sets(res[mask], sv[mask]);
        for (int bit = 1 << n    - 1; bit; bit >>= 1) {
            if (!(mask & bit)) continue;
            tmp = mask & ~bit;
            if (!used[tmp]) continue;
            if (res[tmp] != -1) res[tmp] = merge_sets(res[tmp], res[mask]);
            else res[tmp] = res[mask];
        }
    }

    printf("%d", cnt);
    return 0;
}

int main() {
#if _DEBUG
    freopen("input.txt", "r", stdin);
    freopen("output.txt", "w", stdout);
#endif
    //printf("Case #%d: ", i + 1);
    solve();
#if _DEBUG
    //while(1);
#endif
    return 0;
}


#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <iostream>
#include <vector>
#include <algorithm>
#include <cmath>
#include <set>
#include <map>
#include <unordered_map>
#include <tuple>
#include <functional>
#include <string>
#include <stack>
#include <string.h>
#include <queue>
#include <numeric>
#include <climits>
#include <array>
#include <bitset>
#include <iomanip>

using namespace std;

using ll = long long;
using ull = unsigned long long;
const int K = 22;
const int N = (1 << K) + 10;
const int M = 1e5 + 10;
const int SN = 1000;
const int LG = 21;
const ll mod = 998244353;

using namespace std;

int arr[N];
int used[N];
int res[N];
int sv[N];

int dsu[N];

int get_set(int v) {
    if (dsu[v] == v) return v;
    return dsu[v] = get_set(dsu[v]);
}
int cnt = 0;

int merge_sets(int a, int b) {
    a = get_set(a);
    b = get_set(b);
    if (a == b) return a;
    cnt--;
    if (rand() % 2) {
        swap(a, b);
    }
    return dsu[b] = a;
}

bool is_null = false;

int solve() {
    int n, m;
    scanf("%d%d", &n, &m);
    int nwm = m;
    for (int i = 0; i < N; ++i) {
        res[i] = sv[i] = -1;
    }
    for (int i = 1; i <= m; ++i) {
        scanf("%d", arr + i);
        cnt++;
        is_null = !arr[i];
        used[arr[i]] = 1;
        dsu[arr[i]] = arr[i];
        sv[arr[i]] = arr[i];
    }

    //if (is_null)return printf("1"), 0;
    int tmp;
    for (int mask = 0; mask < N; ++mask) {
        if (!used[mask]) continue;
        for (int bit = 1 << n - 1; bit; bit >>= 1) {
            if (mask & bit) continue;
            tmp = mask | bit;
            used[tmp] = 1;
            if (!sv[tmp]) sv[tmp] = sv[mask];
        }
    }
    int b = (1 << n) - 1;
    for (int i = 1; i <= m; ++i) {
        int inv = ~arr[i] & b;
        if (!used[inv]) continue;
        if (res[inv]!=-1) res[inv] = merge_sets(arr[i], res[inv]);
        else res[inv] = get_set(arr[i]);

    }
    for (int mask = (1 << n) - 1; mask; --mask) {
        if (!used[mask]) continue;
        if (res[mask] == -1) continue;
        if (sv[mask] != -1) res[mask] = merge_sets(res[mask], sv[mask]);
        for (int bit = 1 << n    - 1; bit; bit >>= 1) {
            if (!(mask & bit)) continue;
            tmp = mask & ~bit;
            if (!used[tmp]) continue;
            if (res[tmp] != -1) res[tmp] = merge_sets(res[tmp], res[mask]);
            else res[tmp] = res[mask];
        }
    }

    printf("%d", cnt);
    return 0;
}

int main() {
#if _DEBUG
    freopen("input.txt", "r", stdin);
    freopen("output.txt", "w", stdout);
#endif
    //printf("Case #%d: ", i + 1);
    solve();
#if _DEBUG
    //while(1);
#endif
    return 0;
}


#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <iostream>
#include <vector>
#include <algorithm>
#include <cmath>
#include <set>
#include <map>
#include <unordered_map>
#include <tuple>
#include <functional>
#include <string>
#include <stack>
#include <string.h>
#include <queue>
#include <numeric>
#include <climits>
#include <array>
#include <bitset>
#include <iomanip>

using namespace std;

using ll = long long;
using ull = unsigned long long;
const int K = 22;
const int N = (1 << K) + 10;
const int M = 1e5 + 10;
const int SN = 1000;
const int LG = 21;
const ll mod = 998244353;

using namespace std;

int arr[N];
int used[N];
int res[N];
int sv[N];
int chck[N];
int tcnt[N];

int dsu[N];

int get_set(int v) {
    if (dsu[v] == v) return v;
    return dsu[v] = get_set(dsu[v]);
}
int cnt = 0;

int merge_sets(int a, int b) {
    a = get_set(a);
    b = get_set(b);
    if (a == b) return a;
    cnt--;
    if (rand() % 2) {
        swap(a, b);
    }
    return dsu[b] = a;
}

bool is_null = false;

int solve() {
    int n, m;
    scanf("%d%d", &n, &m);
    int nwm = m;
    for (int i = 0; i < N; ++i) {
        res[i] = sv[i] = -1;
    }
    for (int i = 1; i <= m; ++i) {
        scanf("%d", arr + i);
        tcnt[arr[i]]++;
        if (!used[arr[i]]) cnt++;
        is_null = !arr[i];
        used[arr[i]] = 1;
        dsu[arr[i]] = arr[i];
        sv[arr[i]] = arr[i];
    }

    if (!n)return printf("1"), 0;
    int tmp;
    for (int mask = 0; mask < N; ++mask) {
        if (!used[mask]) continue;
        for (int bit = 1 << n - 1; bit; bit >>= 1) {
            if (mask & bit) continue;
            tmp = mask | bit;
            used[tmp] = 1;
            if (sv[tmp] == -1) sv[tmp] = sv[mask];
        }
    }
    int b = (1 << n) - 1;
    for (int i = 1; i <= m; ++i) {
        int inv = ~arr[i] & b;
        if (chck[arr[i]]) continue;
        if (!used[inv]) {
            cnt+= tcnt[arr[i]]-1;
            chck[arr[i]] = 1;
            continue;
        }
        if (res[inv]!=-1) res[inv] = merge_sets(arr[i], res[inv]);
        else res[inv] = get_set(arr[i]);

    }
    for (int mask = (1 << n) - 1; mask; --mask) {
        if (!used[mask]) continue;
        if (res[mask] == -1) continue;
        if (sv[mask] != -1) res[mask] = merge_sets(res[mask], sv[mask]);
        for (int bit = 1 << n    - 1; bit; bit >>= 1) {
            if (!(mask & bit)) continue;
            tmp = mask & ~bit;
            if (!used[tmp]) continue;
            if (res[tmp] != -1) res[tmp] = merge_sets(res[tmp], res[mask]);
            else res[tmp] = res[mask];
        }
    }

    printf("%d", cnt);
    return 0;
}

int main() {
#if _DEBUG
    freopen("input.txt", "r", stdin);
    freopen("output.txt", "w", stdout);
#endif
    //printf("Case #%d: ", i + 1);
    solve();
#if _DEBUG
    //while(1);
#endif
    return 0;
}


#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <iostream>
#include <vector>
#include <algorithm>
#include <cmath>
#include <set>
#include <map>
#include <unordered_map>
#include <tuple>
#include <functional>
#include <string>
#include <stack>
#include <string.h>
#include <queue>
#include <numeric>
#include <climits>
#include <array>
#include <bitset>
#include <iomanip>

using namespace std;

using ll = long long;
using ull = unsigned long long;
const int K = 22;
const int N = (1 << K) + 10;
const int M = 1e5 + 10;
const int SN = 1000;
const int LG = 21;
const ll mod = 998244353;

using namespace std;

int arr[N];
int used[N];
int res[N];
int sv[N];
int chck[N];
int tcnt[N];

int dsu[N];

int get_set(int v) {
    if (dsu[v] == v) return v;
    return dsu[v] = get_set(dsu[v]);
}
int cnt = 0;

int merge_sets(int a, int b) {
    a = get_set(a);
    b = get_set(b);
    if (a == b) return a;
    cnt--;
    if (rand() % 2) {
        swap(a, b);
    }
    return dsu[b] = a;
}

bool is_null = false;

int solve() {
    int n, m;
    scanf("%d%d", &n, &m);
    int nwm = m;
    for (int i = 0; i < N; ++i) {
        res[i] = sv[i] = -1;
    }
    for (int i = 1; i <= m; ++i) {
        scanf("%d", arr + i);
        tcnt[arr[i]]++;
        if (!used[arr[i]]) cnt++;
        is_null = !arr[i];
        used[arr[i]] = 1;
        dsu[arr[i]] = arr[i];
        sv[arr[i]] = arr[i];
    }

    //if (is_null)return printf("1"), 0;
    int tmp;
    for (int mask = 0; mask < N; ++mask) {
        if (!used[mask]) continue;
        for (int bit = 1 << n - 1; bit; bit >>= 1) {
            if (mask & bit) continue;
            tmp = mask | bit;
            used[tmp] = 1;
            if (!sv[tmp]) sv[tmp] = sv[mask];
        }
    }
    int b = (1 << n) - 1;
    for (int i = 1; i <= m; ++i) {
        int inv = ~arr[i] & b;
        if (chck[arr[i]]) continue;
        if (!used[inv]) {
            cnt+= tcnt[arr[i]]-1;
            chck[arr[i]] = 1;
            continue;
        }
        if (res[inv]!=-1) res[inv] = merge_sets(arr[i], res[inv]);
        else res[inv] = get_set(arr[i]);

    }
    for (int mask = (1 << n) - 1; mask; --mask) {
        if (!used[mask]) continue;
        if (res[mask] == -1) continue;
        if (sv[mask] != -1) res[mask] = merge_sets(res[mask], sv[mask]);
        for (int bit = 1 << n    - 1; bit; bit >>= 1) {
            if (!(mask & bit)) continue;
            tmp = mask & ~bit;
            if (!used[tmp]) continue;
            if (res[tmp] != -1) res[tmp] = merge_sets(res[tmp], res[mask]);
            else res[tmp] = res[mask];
        }
    }

    printf("%d", cnt);
    return 0;
}

int main() {
#if _DEBUG
    freopen("input.txt", "r", stdin);
    freopen("output.txt", "w", stdout);
#endif
    //printf("Case #%d: ", i + 1);
    solve();
#if _DEBUG
    //while(1);
#endif
    return 0;
}


#include <iostream>
#include <stdio.h>
#include <algorithm>
#include <vector>

using namespace std;

template <class T> void write(T x){
    if(x >> 1) write(x >> 1);
    cout << (x & 1);
}
int fastread(){
    int r = 0;
    char c;
    while(c = getchar(),c < '0' || c > '9');
    r = c - '0';
    while(c = getchar(),c >= '0' && c <= '9') r = r * 10 + (c - '0');
    return r;
}

const int N = 1 << 23;

int n,m;
int f[N],a[N],cnt[N],g[N];
bool c[N];

int find(int u){
    return u == g[u] ? u : (g[u] = find(g[u]));
}
void join(int u,int v){
    int x = find(u),y = find(v);
    g[find(u)] = find(v);
}
int main(){

    n = fastread(); m = fastread();
    int k = (1 << n) - 1;
    for(int i = 1; i <= m; ++i){
        a[i] = fastread();
        g[i] = i;
        ++cnt[a[i]];
        //ver[a[i]].push_back(i);
    }

    // counting
    for(int i = 0; i < n; ++i) for(int j = 0; j <= k; ++j) if(j & (1 << i)) cnt[j] += cnt[j ^ (1 << i)];

    int total = m;
    for(int i = k; i >= 0; --i){
        if(!cnt[i]) continue;
        int j = k ^ i;
        if(cnt[j]){
            if(!f[i]) f[i] = ++total;
            g[total] = total;
            if(f[j]) join(f[i],f[j]);
            else f[j] = total;
        }
        /*if(f[i]){
            for(int v : ver[i]){
                join(v,f[i]);
            }
        }*/
        // down
        if(f[i]){
            for(int j = 0; j < n; ++j) if(i & (1 << j)){
                int s = i ^ (1 << j);
                if(!cnt[s]) continue;
                    if(f[s]) join(f[s],f[i]);
                    else f[s] = f[i];
                }
        }
    }

    for(int i = 1; i <= m; ++i) if(f[a[i]]){
        join(i,f[a[i]]);
    }

    /*for(int i = 0; i <= k; ++i){
        int j = k ^ i;
        if(cnt[i] && cnt[j]){
            for(int x = 1; x <= m; ++x) if((a[x] & i) == a[x])
            for(int y = 1; y <= m; ++y) if((a[y] & j) == a[y]) join(x,y);
        }
    }*/

    int res = 0;

    for(int i = 1; i <= m; ++i){
        if(!c[find(i)]){
            c[g[i]] = 1;
            ++res;
        }
    }
    printf("%d",res);

    return 0;
}


#include <iostream>
#include <stdio.h>
#include <algorithm>
#include <vector>

using namespace std;

int fastread(){
    int r = 0;
    char c;
    while(c = getchar(),c < '0' || c > '9');
    r = c - '0';
    while(c = getchar(),c >= '0' && c <= '9') r = r * 10 + (c - '0');
    return r;
}

const int N = 1 << 23;

int n,m;
int f[N],a[N],cnt[N];
vector <int> ver[N];
bool c[N];

int find(int u){
    return a[u] != u ? (a[u] = find(a[u])) : u;
}
void join(int u,int v){
    a[find(u)] = find(v);
}
void down(int i,int v){
    for(int j = 0; j < n; ++j) if(i & (1 << j)){
        int k = i ^ (1 << j);
        if(f[k]) join(k,v);
        else f[k] = v;
    }
}
int main(){

    n = fastread(); m = fastread();
    for(int i = 1; i <= m; ++i){
        int x = fastread();
        ver[x].push_back(i);
        ++cnt[x];
        a[i] = i;
    }

    //
    int k = (1 << n) - 1;
    for(int i = 0; i < n; ++i){
        for(int msk = 0; msk <= k; ++msk) if(msk & (1 << i)) cnt[msk] += cnt[msk ^ (1 << i)];
    }
    int total = n;
    for(int i = k; i >= 0; --i){
        int j = k ^ i;
        if(cnt[i]){
            if(f[i]){
                for(int v : ver[i]){
                    join(a[v],f[i]);
                }
                if(f[j]) join(f[i],f[j]);
                else f[j] = f[i];
            }else if(!cnt[j]){
            }else{
                ++total;
                down(i,total);
                if(f[j]) join(total,f[j]);
                else f[j] = total;
            }
        }
    }

    int res = 0;
    for(int i = 1; i <= m; ++i){
        a[i] = find(a[i]);
        if(!c[a[i]]){
            c[a[i]] = 1;
            ++res;
        }
    }

    printf("%d",res);

    return 0;
}


#include <iostream>
#include <stdio.h>
#include <algorithm>
#include <vector>

using namespace std;

template <class T> void write(T x){
    if(x >> 1) write(x >> 1);
    cout << (x & 1);
}
int fastread(){
    int r = 0;
    char c;
    while(c = getchar(),c < '0' || c > '9');
    r = c - '0';
    while(c = getchar(),c >= '0' && c <= '9') r = r * 10 + (c - '0');
    return r;
}

const int N = 1 << 23;

int n,m;
int cnt[N],g[N],a[(1 << 22) + 11];
bool d[N];

int find(int u){
    return u == g[u] ? u : (g[u] = find(g[u]));
}
void join(int u,int v){
    int x = find(u),y = find(v);
    g[find(u)] = find(v);
}
int main(){

    n = fastread(); m = fastread();
    int k = (1 << n) - 1;
    for(int i = 1; i <= m; ++i){
        a[i] = fastread();
        ++cnt[a[i]];
    }

    // counting
    for(int i = 0; i < n; ++i) for(int j = 0; j <= k; ++j) if(j & (1 << i)) cnt[j] += cnt[j ^ (1 << i)];

    for(int i = k; i >= 0; --i){
        g[i] = i;
    }
    for(int i = k; i >= 0; --i){
        if(!cnt[i]) continue;
        int j = k ^ i;
        if(cnt[j]){
            for(int v = 0; v < n; ++v) if(i & (1 << v)){
                if(cnt[i ^ (1 << v)]) join(i,i ^ (1 << v));
            }
            join(i,j);
        }
    }

    int res = 0;

    for(int i = 1; i <= m; ++i) if(!d[find(a[i])]){
        d[g[a[i]]] = 1;
        ++res;
    }

    printf("%d",res);

    return 0;
}


#include <iostream>
#include <stdio.h>
#include <algorithm>
#include <vector>

using namespace std;

template <class T> void write(T x){
    if(x >> 1) write(x >> 1);
    cout << (x & 1);
}
int fastread(){
    int r = 0;
    char c;
    while(c = getchar(),c < '0' || c > '9');
    r = c - '0';
    while(c = getchar(),c >= '0' && c <= '9') r = r * 10 + (c - '0');
    return r;
}

const int N = 1 << 23;

int n,m;
int f[N],a[N],cnt[N],g[N];
vector <int> ver[N];
bool c[N];

int find(int u){
    return u == g[u] ? u : (g[u] = find(g[u]));
}
void join(int u,int v){
    int x = find(u),y = find(v);
    g[find(u)] = find(v);
}
int main(){

    n = fastread(); m = fastread();
    int k = (1 << n) - 1;
    for(int i = 1; i <= m; ++i){
        a[i] = fastread();
        g[i] = i;
        ++cnt[a[i]];
        ver[a[i]].push_back(i);
    }

    // counting
    for(int i = 0; i < n; ++i) for(int j = 0; j <= k; ++j) if(j & (1 << i)) cnt[j] += cnt[j ^ (1 << i)];

    int total = m;
    for(int i = k; i >= 0; --i){
        if(!cnt[i]) continue;
        int j = k ^ i;
        if(cnt[j]){
            if(!f[i]) f[i] = ++total;
            g[total] = total;
            if(f[j]) join(f[i],f[j]);
            else f[j] = total;
        }
        if(f[i]){
            for(int v : ver[i]){
                join(v,f[i]);
            }
        }
        // down
        if(f[i]){
            for(int j = 0; j < n; ++j) if(i & (1 << j)){
                int s = i ^ (1 << j);
                if(!cnt[s]) continue;
                    if(f[s]) join(f[s],f[i]);
                    else f[s] = f[i];
                }
        }
    }

    /*for(int i = 1; i <= m; ++i) if(f[a[i]]){
        join(i,f[a[i]]);
    }*/

    /*for(int i = 0; i <= k; ++i){
        int j = k ^ i;
        if(cnt[i] && cnt[j]){
            for(int x = 1; x <= m; ++x) if((a[x] & i) == a[x])
            for(int y = 1; y <= m; ++y) if((a[y] & j) == a[y]) join(x,y);
        }
    }*/

    int res = 0;

    for(int i = 1; i <= m; ++i){
        if(!c[find(i)]){
            c[g[i]] = 1;
            ++res;
        }
    }
    printf("%d",res);

    return 0;
}


#include <iostream>
#include <stdio.h>
#include <algorithm>
#include <vector>

using namespace std;

template <class T> void write(T x){
    if(x >> 1) write(x >> 1);
    cout << (x & 1);
}
int fastread(){
    int r = 0;
    char c;
    while(c = getchar(),c < '0' || c > '9');
    r = c - '0';
    while(c = getchar(),c >= '0' && c <= '9') r = r * 10 + (c - '0');
    return r;
}

const int N = 1 << 23;

int n,m;
int f[N],cnt[N],g[N],a[(1 << 22) + 11];
vector <int> ver[1 << 22];
bool c[N];

int find(int u){
    return u == g[u] ? u : (g[u] = find(g[u]));
}
void join(int u,int v){
    int x = find(u),y = find(v);
    g[find(u)] = find(v);
}
int main(){

    n = fastread(); m = fastread();
    int k = (1 << n) - 1;
    for(int i = 1; i <= m; ++i){
        a[i] = fastread();
        g[i] = i;
        ++cnt[a[i]];
        ver[a[i]].push_back(i);
    }

    // counting
    for(int i = 0; i < n; ++i) for(int j = 0; j <= k; ++j) if(j & (1 << i)) cnt[j] += cnt[j ^ (1 << i)];

    int total = m;
    for(int i = k; i >= 0; --i){
        if(!cnt[i]) continue;
        int j = k ^ i;
        if(cnt[j]){
            if(!f[i]) f[i] = ++total;
            g[total] = total;
            if(f[j]) join(f[i],f[j]);
            else f[j] = total;
        }
        if(f[i]){
            for(int v : ver[i]){
                join(v,f[i]);
            }
        }
        // down
        if(f[i]){
            for(int j = 0; j < n; ++j) if(i & (1 << j)){
                int s = i ^ (1 << j);
                if(!cnt[s]) continue;
                    if(f[s]) join(f[s],f[i]);
                    else f[s] = f[i];
                }
        }
    }

    /*for(int i = 1; i <= m; ++i) if(f[a[i]]){
        join(i,f[a[i]]);
    }*/

    /*for(int i = 0; i <= k; ++i){
        int j = k ^ i;
        if(cnt[i] && cnt[j]){
            for(int x = 1; x <= m; ++x) if((a[x] & i) == a[x])
            for(int y = 1; y <= m; ++y) if((a[y] & j) == a[y]) join(x,y);
        }
    }*/

    int res = 0;

    for(int i = 1; i <= m; ++i){
        if(!c[find(i)]){
            c[g[i]] = 1;
            ++res;
        }
    }
    printf("%d",res);

    return 0;
}


#include <iostream>
#include <stdio.h>
#include <algorithm>
#include <vector>

using namespace std;

template <class T> void write(T x){
    if(x >> 1) write(x >> 1);
    cout << (x & 1);
}
int fastread(){
    int r = 0;
    char c;
    while(c = getchar(),c < '0' || c > '9');
    r = c - '0';
    while(c = getchar(),c >= '0' && c <= '9') r = r * 10 + (c - '0');
    return r;
}

const int N = 1 << 23;

int n,m;
int cnt[N],g[N],a[(1 << 22) + 11];
bool d[N];

int find(int u){
    return u == g[u] ? u : (g[u] = find(g[u]));
}
void join(int u,int v){
    int x = find(u),y = find(v);
    g[find(u)] = find(v);
}
int main(){

    n = fastread(); m = fastread();
    int k = (1 << n) - 1;
    for(int i = 1; i <= m; ++i){
        a[i] = fastread();
        ++cnt[a[i]];
    }

    // counting
    for(int i = 0; i < n; ++i) for(int j = 0; j <= k; ++j) if(j & (1 << i)) cnt[j] += cnt[j ^ (1 << i)];

    for(int i = k; i >= 0; --i){
        g[i] = i;
    }
    for(int i = k; i >= 0; --i){
        if(!cnt[i]) continue;
        int j = k ^ i;
        if(cnt[j]){
            for(int v = 0; v < n; ++v) if(i & (1 << v)){
                join(i,i ^ (1 << v));
            }
        }
    }

    int res = 0;

    for(int i = 1; i <= m; ++i) if(!d[find(a[i])]){
        d[g[a[i]]] = 1;
        ++res;
    }

    printf("%d",res);

    return 0;
}


#include <iostream>
#include <stdio.h>
#include <algorithm>
#include <vector>

using namespace std;

template <class T> void write(T x){
    if(x >> 1) write(x >> 1);
    cout << (x & 1);
}
int fastread(){
    int r = 0;
    char c;
    while(c = getchar(),c < '0' || c > '9');
    r = c - '0';
    while(c = getchar(),c >= '0' && c <= '9') r = r * 10 + (c - '0');
    return r;
}

const int N = 1 << 23;

int n,m;
int f[N],a[N],cnt[N],g[N];
vector <int> ver[N];
bool c[N];

int find(int u){
    return u == g[u] ? u : (g[u] = find(g[u]));
}
void join(int u,int v){
    int x = find(u),y = find(v);
    g[find(u)] = find(v);
}
int main(){

    n = fastread(); m = fastread();
    int k = (1 << n) - 1;
    for(int i = 1; i <= m; ++i){
        a[i] = fastread();
        g[i] = i;
        ++cnt[a[i]];
        ver[a[i]].push_back(i);
    }

    // counting
    for(int i = 0; i < n; ++i) for(int j = 0; j <= k; ++j) if(j & (1 << i)) cnt[j] += cnt[j ^ (1 << i)];

    int total = m;
    for(int i = k; i >= 0; --i){
        if(!cnt[i]) continue;
        int j = k ^ i;
        if(cnt[j]){
            if(!f[i]) f[i] = ++total;
            g[total] = total;
            if(f[j]) join(f[i],f[j]);
            else f[j] = total;
        }
        if(f[i]){
            for(int v : ver[i]){
                join(v,f[i]);
            }
        }
        // down
        if(f[i]){
            for(int j = 0; j < n; ++j) if(i & (1 << j)){
                int s = i ^ (1 << j);
                if(!cnt[s]) continue;
                    if(f[s]) join(f[s],f[i]);
                    else f[s] = f[i];
                }
        }
    }

    /*for(int i = 0; i <= k; ++i){
        int j = k ^ i;
        if(cnt[i] && cnt[j]){
            for(int x = 1; x <= m; ++x) if((a[x] & i) == a[x])
            for(int y = 1; y <= m; ++y) if((a[y] & j) == a[y]) join(x,y);
        }
    }*/

    int res = 0;
    for(int i = 1; i <= m; ++i){
        if(!c[find(i)]){
            c[g[i]] = 1;
            ++res;
        }
    }
    printf("%d",res);

    return 0;
}


#include <bits/stdc++.h>
using namespace std;
#define mp make_pair
#define pb push_back
#define len(a) (int)a.size()
#define fi first
#define sc second
#define d1(w) cerr<<#w<<":"<<w<<endl;
#define d2(w,c) cerr<<#w<<":"<<w<<" "<<#c<<":"<<c<<endl;
#define d3(w,c,z) cerr<<#w<<":"<<w<<" "<<#c<<":"<<c<<" "<<#z<<":"<<z<<endl;
#define left ind+ind
#define right ind+ind+1
#define mid (l+r)/2
#define endl '\n'
#define bit __builtin_popcount

typedef long long int ll;

const int maxn = 620;
const long long LINF = 1e18;
const int LOG = 31;
const int INF = 1e9 + 5;
const int P = 31;
const int ALP = 22;
const int N = 25;
const int M = (1 << 24) + 5;
const int SQ = 350;
const int MOD = 1e9 + 7;

typedef long long int lli;
typedef pair<int,int> pii;

int n,m,ans,magic,a[M],dad[M],mark[M];
bool have[M],vis[M];

void dfs(int cur) {
	if (vis[cur]) return;
	vis[cur] = true;
	for (int i = 0 ; i <= n ; i++)
		if (cur & (1 << i))
			dfs(cur - (1 << i));
	if (have[cur])
		dfs(cur ^ magic);
}

int main() {

	ios_base::sync_with_stdio(false);
	cin.tie(NULL); cout.tie(NULL);

	cin >> n >> m;

	for (int i = 0 ; i < n ; i++)
		magic += (1 << i);

	for (int i = 1 ; i <= m ; i++) {
		cin >> a[i];
		have[a[i]] = true;
	}

	for (int i = 0 ; i < (1 << n) ; i++) {
		if (have[a[i]] && vis[a[i]] == false) {
			dfs(magic ^ a[i]);
			ans++;
		}
	}

	cout << ans << endl;

}


#include <bits/stdc++.h>
using namespace std;
#define mp make_pair
#define pb push_back
#define len(a) (int)a.size()
#define fi first
#define sc second
#define d1(w) cerr<<#w<<":"<<w<<endl;
#define d2(w,c) cerr<<#w<<":"<<w<<" "<<#c<<":"<<c<<endl;
#define d3(w,c,z) cerr<<#w<<":"<<w<<" "<<#c<<":"<<c<<" "<<#z<<":"<<z<<endl;
#define left ind+ind
#define right ind+ind+1
#define mid (l+r)/2
#define endl '\n'
#define bit __builtin_popcount

typedef long long int ll;

const int maxn = 620;
const long long LINF = 1e18;
const int LOG = 31;
const int INF = 1e9 + 5;
const int P = 31;
const int ALP = 22;
const int N = 25;
const int M = (1 << 24) + 5;
const int SQ = 350;
const int MOD = 1e9 + 7;

typedef long long int lli;
typedef pair<int,int> pii;

int n,m,ans,magic,a[M],dad[M],mark[M];
bool have[M],vis[M];

void dfs(int cur) {
	if (vis[cur]) return;
	vis[cur] = true;
	for (int i = 0 ; i <= n ; i++)
		if (cur & (1 << i))
			dfs(cur - (1 << i));
}

int main() {

	ios_base::sync_with_stdio(false);
	cin.tie(NULL); cout.tie(NULL);

	cin >> n >> m;

	for (int i = 0 ; i < n ; i++)
		magic += (1 << i);

	for (int i = 1 ; i <= m ; i++) {
		cin >> a[i];
		have[a[i]] = true;
	}

	for (int i = 1 ; i <= m ; i++) {
		int tut = magic ^ a[i];
		if(vis[magic ^ a[i]] == false && have[magic ^ a[i]]) {
			ans++;
			dfs(magic ^ a[i]);
		}
	}

	cout << ans << endl;

}


#include <bits/stdc++.h>
using namespace std;
#define mp make_pair
#define pb push_back
#define len(a) (int)a.size()
#define fi first
#define sc second
#define d1(w) cerr<<#w<<":"<<w<<endl;
#define d2(w,c) cerr<<#w<<":"<<w<<" "<<#c<<":"<<c<<endl;
#define d3(w,c,z) cerr<<#w<<":"<<w<<" "<<#c<<":"<<c<<" "<<#z<<":"<<z<<endl;
#define left ind+ind
#define right ind+ind+1
#define mid (l+r)/2
#define endl '\n'
#define bit __builtin_popcount

typedef long long int ll;

const int maxn = 620;
const long long LINF = 1e18;
const int LOG = 31;
const int INF = 1e9 + 5;
const int P = 31;
const int ALP = 22;
const int N = 25;
const int M = (1 << 24) + 5;
const int SQ = 350;
const int MOD = 1e9 + 7;

typedef long long int lli;
typedef pair<int,int> pii;

int n,m,ans,magic,a[M],dad[M],mark[M];
bool have[M],vis[M];

int find(int x) {
	if (x == dad[x]) return x;
	return dad[x] = find(dad[x]);
}

void merge(int x,int y) {
	int dy = find(y);
	int dx = find(x);
	if (dy == dx) return;
	dad[dx] = dy;
}

void dfs(int cur,int back) {
	if (vis[cur]) return;
	vis[cur] = true;
	merge(cur,back);
	for (int i = 0 ; i <= n ; i++)
		if (cur & (1 << i))
			dfs(cur - (1 << i),cur);
}

int main() {

	ios_base::sync_with_stdio(false);
	cin.tie(NULL); cout.tie(NULL);

	cin >> n >> m;

	for (int i = 0 ; i < n ; i++)
		magic += (1 << i);

	for (int i = 0 ; i < (1 << n) ; i++)
		dad[i] = i;

	for (int i = 1 ; i <= m ; i++) {
		cin >> a[i];
		int tut = magic ^ a[i];
		have[a[i]] = true;
	}

	for (int i = 1 ; i <= m ; i++) {
		int tut = magic ^ a[i];
		dfs(magic ^ a[i],a[i]);
	}

	for (int i = 0 ; i < (1 << n) ; i++)
		if (have[i]) {
			if (mark[find(i)] == 0) ans++;
			mark[find(i)] = 1;
		}
	cout << ans << endl;

}


#include <bits/stdc++.h>
using namespace std;
#define mp make_pair
#define pb push_back
#define len(a) (int)a.size()
#define fi first
#define sc second
#define d1(w) cerr<<#w<<":"<<w<<endl;
#define d2(w,c) cerr<<#w<<":"<<w<<" "<<#c<<":"<<c<<endl;
#define d3(w,c,z) cerr<<#w<<":"<<w<<" "<<#c<<":"<<c<<" "<<#z<<":"<<z<<endl;
#define left ind+ind
#define right ind+ind+1
#define mid (l+r)/2
#define endl '\n'
#define bit __builtin_popcount

typedef long long int ll;

const int maxn = 620;
const long long LINF = 1e18;
const int LOG = 31;
const int INF = 1e9 + 5;
const int P = 31;
const int ALP = 22;
const int N = 25;
const int M = (1 << 24) + 5;
const int SQ = 350;
const int MOD = 1e9 + 7;

typedef long long int lli;
typedef pair<int,int> pii;

int n,m,ans,magic,a[M],dad[M],mark[M];
bool have[M],vis[M];

int find(int x) {
	if (x == dad[x]) return x;
	return dad[x] = find(dad[x]);
}

void merge(int x,int y) {
	int dy = find(y);
	int dx = find(x);
	if (dy == dx) return;
	dad[dx] = dy;
}

void dfs(int cur,int back) {
	vis[cur] = true;
	merge(cur,back);
	for (int i = 0 ; i <= n ; i++)
		if (cur & (1 << i) && vis[cur - (1 << i)] == false)
			dfs(cur - (1 << i),cur);
}

int main() {

	ios_base::sync_with_stdio(false);
	cin.tie(NULL); cout.tie(NULL);

	cin >> n >> m;

	for (int i = 0 ; i < n ; i++)
		magic += (1 << i);

	for (int i = 0 ; i < (1 << n) ; i++)
		dad[i] = i;

	for (int i = 1 ; i <= m ; i++) {
		cin >> a[i];
		int tut = magic ^ a[i];
		have[a[i]] = true;
	}

	for (int i = 1 ; i <= m ; i++) {
		int tut = magic ^ a[i];
		if(vis[magic ^ a[i]] == false)
			dfs(magic ^ a[i],a[i]);
	}

	for (int i = 1 ; i <= m ; i++) {
		ans += (++mark[find(a[i])] == 1);
	}
	cout << ans << endl;

}


#include <bits/stdc++.h>
using namespace std;
#define mp make_pair
#define pb push_back
#define len(a) (int)a.size()
#define fi first
#define sc second
#define d1(w) cerr<<#w<<":"<<w<<endl;
#define d2(w,c) cerr<<#w<<":"<<w<<" "<<#c<<":"<<c<<endl;
#define d3(w,c,z) cerr<<#w<<":"<<w<<" "<<#c<<":"<<c<<" "<<#z<<":"<<z<<endl;
#define left ind+ind
#define right ind+ind+1
#define mid (l+r)/2
#define endl '\n'
#define bit __builtin_popcount

typedef long long int ll;

const int maxn = 620;
const long long LINF = 1e18;
const int LOG = 31;
const int INF = 1e9 + 5;
const int P = 31;
const int ALP = 22;
const int N = 25;
const int M = (1 << 22) + 5;
const int SQ = 350;
const int MOD = 1e9 + 7;

typedef long long int lli;
typedef pair<int,int> pii;

int n,m,ans,magic,a[M];
bool have[M],vis[M];

void dfs(int cur) {
	if (vis[cur]) return;
	vis[cur] = true;
	for (int i = 0 ; i <= n ; i++)
		if (cur & (1 << i))
			dfs(cur - (1 << i));
	if (have[cur])
		dfs(cur ^ magic);
}

int main() {

	ios_base::sync_with_stdio(false);
	cin.tie(NULL); cout.tie(NULL);

	cin >> n >> m;

	for (int i = 0 ; i < n ; i++)
		magic += (1 << i);

	for (int i = 1 ; i <= m ; i++) {
		cin >> a[i];
		have[a[i]] = true;
	}

	for (int i = 0 ; i < (1 << n) ; i++) {
		if (have[a[i]] && vis[a[i]] == false) {
			dfs(magic ^ a[i]);
			ans++;
		}
	}

	cout << ans << endl;

}


#include <bits/stdc++.h>
using namespace std;
#define mp make_pair
#define pb push_back
#define len(a) (int)a.size()
#define fi first
#define sc second
#define d1(w) cerr<<#w<<":"<<w<<endl;
#define d2(w,c) cerr<<#w<<":"<<w<<" "<<#c<<":"<<c<<endl;
#define d3(w,c,z) cerr<<#w<<":"<<w<<" "<<#c<<":"<<c<<" "<<#z<<":"<<z<<endl;
#define left ind+ind
#define right ind+ind+1
#define mid (l+r)/2
#define endl '\n'
#define bit __builtin_popcount

typedef long long int ll;

const int maxn = 620;
const long long LINF = 1e18;
const int LOG = 31;
const int INF = 1e9 + 5;
const int P = 31;
const int ALP = 22;
const int N = 25;
const int M = (1 << 24) + 5;
const int SQ = 350;
const int MOD = 1e9 + 7;

typedef long long int lli;
typedef pair<int,int> pii;

int n,m,ans,magic,a[M],dad[M],mark[M];
bool have[M],vis[M];

int find(int x) {
	if (x == dad[x]) return x;
	return dad[x] = find(dad[x]);
}

void merge(int x,int y) {
	int dy = find(y);
	int dx = find(x);
	if (dy == dx) return;
	dad[dx] = dy;
}

void dfs(int cur,int back) {
	if (vis[cur]) return;
	vis[cur] = true;
	merge(cur,back);
	for (int i = 0 ; i <= n ; i++)
		if (cur & (1 << i))
			dfs(cur - (1 << i),cur);
}

int main() {

	ios_base::sync_with_stdio(false);
	cin.tie(NULL); cout.tie(NULL);

	cin >> n >> m;

	for (int i = 0 ; i < n ; i++)
		magic += (1 << i);

	for (int i = 0 ; i < (1 << n) ; i++)
		dad[i] = i;

	for (int i = 1 ; i <= m ; i++) {
		cin >> a[i];
		int tut = magic ^ a[i];
		have[a[i]] = true;
	}

	for (int i = 1 ; i <= m ; i++) {
		int tut = magic ^ a[i];
		dfs(magic ^ a[i],a[i]);
	}

	for (int i = 1 ; i <= m ; i++) {
		ans += (++mark[find(a[i])] == 1);
	}
	cout << ans << endl;

}


#include <iostream>
#include <queue>
#include <vector>
using namespace std;

int main()
{
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
	int n, m;
	cin >> n >> m;
	bool *f;
	vector<int> *v;
	int *a = new int[m];
	for (int i = 0; i < m; i++)
		cin >> a[i];
	v = new vector<int>[(1 << n) + m];
	f = new bool[(1 << n) + m];
	for (int i = 0; i < (1 << n) + m; i++)
		f[i] = 0;
	for (int i = 0; i < m; i++)
	{
		v[(1 << n) + i].push_back(a[i]);
		int noti = 0;
		for (int j = 0; j < n; j++)
			if (((1 << j)&a[i]) == 0)
				noti += (1 << j);
		v[noti].push_back((1 << n) + i);
	}
	int cnt = 0;
	for (int i = (1 << n); i < (1 << n) + m; i++)
		if (f[i] == 0)
		{
			queue<int>q;
			q.push(i);
			while (!q.empty())
			{
				int fr = q.front();
				f[fr] = 1;
				if (fr < (1 << n))
				{
					for (int j = 0; j < n; j++)
					{
						if (((1 << j) | fr) != i && f[(1 << j) | fr] == 0)
						{
							q.push((1 << j) | fr);
						}
					}
				}
				q.pop();
				for (const int &j : v[fr])
				{
					if (!f[j])
						q.push(j);
				}
			}
			cnt++;
		}
	cout << cnt << endl;
	return 0;
}


#include <iostream>
#include <queue>
#include <vector>
using namespace std;

int main()
{
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
	int n, m;
	cin >> n >> m;
	bool *f;
	vector<int> *v;
	int *a = new int[m];
	for (int i = 0; i < m; i++)
		cin >> a[i];
	v = new vector<int>[(1 << n) + m];
	f = new bool[(1 << n) + m];
	for (int i = 0; i < (1 << n) + m; i++)
		f[i] = 0;
	for (int i = 0; i < m; i++)
	{
		v[(1 << n) + i].push_back(a[i]);
		int noti = 0;
		for (int j = 0; j < n; j++)
			if (((1 << j)&a[i]) == 0)
				noti += (1 << j);
		v[noti].push_back((1 << n) + i);
	}
	for (int i = 0; i < (1 << n); i++)
	{
		for (int j = 0; j < n; j++)
		{
			if (((1 << j)|i) != i)
			{
				v[i].push_back(((1 << j)|i));
			}
		}
	}
	int cnt = 0;
	for (int i = (1 << n); i < (1 << n) + m; i++)
		if (f[i] == 0)
		{
			queue<int>q;
			q.push(i);
			while (!q.empty())
			{
				int fr = q.front();
				f[fr] = 1;
				q.pop();
				for (const int &j : v[fr])
				{
					if (!f[j])
						q.push(j);
				}
			}
			cnt++;
		}
	cout << cnt << endl;
	return 0;
}


#include <iostream>
#include <vector>
typedef long long ll;
using namespace std;

int *f;
vector<int> *v;
void dfs(int vr)
{
	f[vr] = 1;
	for (int i : v[vr])
	{
		if (f[i] == 0) dfs(i);
	}
}
int main()
{
	int n, m;
	cin >> n >> m;
	vector<ll> a(m);
	for (int i = 0; i < m; i++)
		cin >> a[i];
	v = new vector<int>[(1 << n) + m];
	f = new int[(1 << n) + m];
	for (int i = 0; i < (1 << n) + m; i++)
		f[i] = 0;
	for (int i = 0; i < m; i++)
	{
		v[(1 << n) + i].push_back(a[i]);
		int noti = 0;
		for (int j = 0; j < n; j++)
			if (((1 << j)&a[i]) == 0)
				noti += (1 << j);
		v[noti].push_back((1 << n) + i);
	}
	for (int i = 0; i < (1 << n); i++)
	{
		for (int j = 0; j < n; j++)
		{
			if (((1 << j)|i) != i)
			{
				v[i].push_back(((1 << j)|i));
			}
		}
	}
	/*for (int i = 0; i < (1 << n) + m; i++)
	{
		cout << i << ":";
		for (int j : v[i])
			cout << j << " ";
		cout << endl;
	}*/
	int cnt = 0;
	for (int i = (1 << n); i < (1 << n) + m; i++)
		if (f[i] == 0)
		{
			dfs(i);
			cnt++;
		}
	cout << cnt << endl;
	return 0;
}


#include <iostream>
#include <queue>
#include <vector>
using namespace std;

int n, m;
int nn(int x)
{
	int noti = 0;
	for (int j = 0; j < n; j++)
		if (((1 << j)&x) == 0)
			noti += (1 << j);
	return noti;
}
int main()
{
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
	cin >> n >> m;
	bool *f;
	bool *a = new bool[(1 << n)*2];
	for (int i = 0; i < (1 << n) * 2; i++)
		a[i] = 0;
	for (int i = 0; i < m; i++)
	{
		int u;
		cin >> u;
		a[(1 << n) + u] = 1;
	}
	f = new bool[(1 << n) * 2];
	for (int i = 0; i < (1 << n) * 2; i++)
		f[i] = 0;
	int cnt = 0;
	for (int i = (1 << n); i < (1 << n) * 2; i++)
		if (f[i] == 0 && a[i] == 1)
		{
			queue<int>q;
			q.push(i);
			f[i] = 1;
			while (!q.empty())
			{
				int fr = q.front();
				q.pop();
				if (fr < (1 << n))
				{
					for (int j = 0; j < n; j++)
					{
						if (((1 << j) | fr) != i && f[(1 << j) | fr] == 0)
						{
							f[(1 << j) | fr] = 1;
							q.push((1 << j) | fr);
						}
					}
					int noti = nn(fr);
					if (a[noti + (1 << n)] == 1 && f[noti + (1 << n)] == 0)
					{
						f[noti + (1 << n)] = 1;
						q.push(noti + (1 << n));
					}
				}
				else
				{
					if (a[fr] == 1 && f[fr - (1 << n)] == 0) // bolo v povodnom vstupe
					{
						f[fr - (1<<n)] = 1;
						q.push(fr - (1 << n));
					}
				}
			}
			cnt++;
		}
	cout << cnt << endl;
	return 0;
}


#include <iostream>
#include <vector>
typedef long long ll;
using namespace std;

bool *f;
vector<int> *v;
void dfs(int vr)
{
	f[vr] = 1;
	for (int i : v[vr])
	{
		if (f[i] == 0) dfs(i);
	}
}
int main()
{
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
	int n, m;
	cin >> n >> m;
	int *a = new int[m];
	for (int i = 0; i < m; i++)
		cin >> a[i];
	v = new vector<int>[(1 << n) + m];
	f = new bool[(1 << n) + m];
	for (int i = 0; i < (1 << n) + m; i++)
		f[i] = 0;
	for (int i = 0; i < m; i++)
	{
		v[(1 << n) + i].push_back(a[i]);
		int noti = 0;
		for (int j = 0; j < n; j++)
			if (((1 << j)&a[i]) == 0)
				noti += (1 << j);
		v[noti].push_back((1 << n) + i);
	}
	for (int i = 0; i < (1 << n); i++)
	{
		for (int j = 0; j < n; j++)
		{
			if (((1 << j)|i) != i)
			{
				v[i].push_back(((1 << j)|i));
			}
		}
	}
	/*for (int i = 0; i < (1 << n) + m; i++)
	{
		cout << i << ":";
		for (int j : v[i])
			cout << j << " ";
		cout << endl;
	}*/
	int cnt = 0;
	for (int i = (1 << n); i < (1 << n) + m; i++)
		if (f[i] == 0)
		{
			dfs(i);
			cnt++;
		}
	cout << cnt << endl;
	return 0;
}


#include<bits/stdc++.h>
#include<ext/pb_ds/assoc_container.hpp>
#include<ext/pb_ds/tree_policy.hpp>
using namespace std;
using namespace __gnu_pbds;
using namespace chrono;
#define all(a) a.begin(), a.end()
typedef long long ll;
typedef vector<int> vi;
typedef vector<ll> vl;
typedef vector<double> vd;
typedef vector<string> vs;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
typedef pair<int, ll> pil;
typedef pair<ll, int> pli;
typedef tuple<int, int, int> tpl;
template<class T>
using Tree = tree<T, null_type, less<T>, rb_tree_tag, tree_order_statistics_node_update>;
template<class T1, class T2>
istream &operator>>(istream &in, pair<T1, T2> &P){
	in >> P.first >> P.second;
	return in;
}
template<class T1, class T2>
ostream &operator<<(ostream &out, const pair<T1, T2> &P){
	out << "(" << P.first << ", " << P.second << ")";
	return out;
}
template<class T>
istream &operator>>(istream &in, vector<T> &arr){
	for(auto &x: arr) in >> x;
	return in;
}
template<class T>
ostream &operator<<(ostream &out, const vector<T> &arr){
	for(auto &x: arr) out << x << ' '; cout << "\n";
	return out;
}
template<class T>
istream &operator>>(istream &in, deque<T> &arr){
	for(auto &x: arr) in >> x;
	return in;
}
template<class T>
ostream &operator<<(ostream &out, const deque<T> &arr){
	for(auto &x: arr) out << x << ' '; cout << "\n";
	return out;
}
mt19937 rnd(time(0));

int main(){
	ios::sync_with_stdio(0);
	cin.tie(0);
	int n, m;
	cin >> n >> m;
	const int mx = 1 << n;
	vector<vi> adj(mx);
	for(int u = 0; u < mx; u ++){
		for(int bit = 0; bit < n; bit ++){
			if(!(u & 1 << bit)){
				adj[u].push_back(u ^ 1 << bit);
			}
		}
	}
	vi visited(mx, 2);
	for(int i = 0; i < m; i ++){
		int u;
		cin >> u;
		visited[u] = 0;
	}
	int res = 0;
	for(int u = 0; u < mx; u ++){
		if(!(visited[u] & 2)){
			res ++;
			visited[u] |= 2;
			vi q{u};
			while(!q.empty()){
				int u = q.back();
				q.pop_back();
				if(!(visited[mx - 1 - u] & 2)){
					visited[mx - 1 - u] |= 2;
					q.push_back(mx - 1 - u);
				}
				for(auto v: adj[u]){
					if(!(visited[v] & 1)){
						visited[v] |= 1;
						q.push_back(v);
					}
				}
			}
		}
	}
	cout << res;
	return 0;
}
/*
*/

//////////////////////////////////////////////////////////////////////////////////////////////////////
//                                                                                //
//                                                                                //
//                                              _____________                                       //
//             ++++++++++                ___------------------\\                                    //
//           +++`+``+`+`++++        ///`````````````````````````````\\                              //
//           ++`+`+``+++`++++  /////```````````````````````````````````\                            //
//           +++`++`+`+``+++/////`````````````````````````````````````````\                         //
//             +++`++`+``+///```````````|```````````````````````````````````\                       //
//          ____++++/++++/`````````````/````````|````````|```````````````````\                      //
//        /  /  / |    //``````````````|````````|```````|````````|````````````\                     //
//       /  /  /  | ///````````/```````|```````||```````|````````|``````\```````\                   //
//       | /  /   |///`````````|``````/````````|````````|````````|```````|```````\                  //
//       |/   |   |//``|```````|``````|````````|`````````|```````|```````|````````\                 //
//       /\___|__//`|``|```````|`    |      ``:|````````|:```````|```````|```|`````|                //
//      /     /  /``|``|``````|/     |        :|     ```:|```````|```````|``++````++                //
//     /     / //```|``|``````|      |        |:        :|    ```|```````|```++``++`\               //
//     |    /  /````|``|``````/    _.::::.    |          |      |    ````|```|`++`\`|               //
//     |   /   |````|``|`````|            `                    |       ``|```++``++`|               //
//     |  /    |````|``|`````|                                 :         |``++````++|               //
//     | /     /````|``|`````|                              _.-:::.      |..`|``.`|.|               //
//     |/     /`````|``|`````|                                     `     |```|````|`|               //
//    /|      |`````|``|`````|                    :'                    .|```|````|.|               //
//   / |      |`````|``|`````|                                         /|-|``|````|`|               //
//  /  |      |`````|```\````|                                        / ||```|````|``\              //
// /   |      |`````|````|```|::                                    /_| ||```|````|``|              //
//            |`````|````|```|:|:.        `.._                    .\___/:|```|````|``|              //
//            |`````\````|```|:|::-          ``:::....           -:|:|:::|```|````|``|              //
//            |``````|```|```|:|::`|.                          .:::|:|:::|```|````|``|              //
//             \`````|```|```|:|::/|--.                     .`:|:::|:|:::/```|````|``|              //
//              |````|```|```\:|:|:|-----             _..-:|:|:|:::|:|::|````|````|`/               //
//              |````|```|````\|:|:|-------.____.....------|/::|:::|:|::|````|````|`|               //
//              |````|```|\````\:|/\___________    ________/\--\:::|:|::|````/````|`|               //
//              |````\```| \```|:/-------------\  /----------\``\::|:|::|```/`````|`|               //
//              |`````|``|  \``|/---------------\/------------\_________|```|`````|`|               //
//                                                                                //
//////////////////////////////////////////////////////////////////////////////////////////////////////
//                                                                                //
//                                        Created by Aeren                                          //
//                                                                                //
//////////////////////////////////////////////////////////////////////////////////////////////////////