题目:
我们规定序列的与和定义为序列中所有元素按位与得到的结果。
如序列 [1,2,3] :其与和结果为1&2&3=0.
若一个序列与和的结果,其二进制表示形式下包含 k 个 1 ,WY则会认为这是他喜欢的序列
现在WY的手里有一个序列了,他想知道,这个的序列的非空子序列中有多少个他喜欢的序列。
法一
dfs
#define int long long
const int N = 25;
int n, k;
int a[N];
int ans;
void dfs(int x, int m)
{
//当x==n时,就证明已经遍历到n,不能再往下了,就开始判断
if(x == n)
{
int s = 0;
for(int i = 0; i < 64; i ++)
/*这一步是在判断有多少个1,>>是右移符号,每次都往右移动,
他默认就是在二进制中进行的,不用特意转换,然后,到第i个位置
判断他是否是1,&1这个符号就是看他是不是1的,因为&是两个都是1的时候才是1,
如果是就s++*/
if(m >> i & 1) s ++;
if(s == k) ans ++;
return; //这个是返回上一层
}
dfs(x + 1, m & a[x]); //这个就是往下进行
dfs(x + 1, m); //这个是不带a[i]的情况
}
signed main()
{
cin >> n >> k;
for(int i = 0; i < n; i ++) cin >> a[i];
dfs(0, -1);
cout << ans << endl;
return 0;
}
法二
这个可以跟分享的上一题做一下呼应
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N = 25;
int n, k, ans;
int a[N];
signed main()
{
cin >> n >> k;
for(int i = 1; i <= n; i ++) cin >> a[i];
/*1<<n是2^n,这一步是在枚举二进制数,二进制数都是由1,0组成的
<<n,表示左移,就是说算是 n位二进制数*/
for(int i = 1; i < (1 << n); i ++)
{
int x = -1;
/*i >> j & 1,是判断这一位上是否是1,如果是1,那就&操作一下,如果不是就不,
其实这个是相当于遍历所有情况,因为每个二进制数是不一样的,所以上面的1,0的
情况也是不一样的,由此就可以照顾到所有情况了*/
for(int j = 0; j < n; j ++)
if(i >> j & 1) x &= a[j + 1];
int cnt = 0;
for(int j = 0; j < 64; j ++)
if(x >> j & 1) cnt ++;
if(cnt == k) ans ++;
}
cout << ans << endl;
return 0;
}