2023河南萌新联赛第(四)场:河南大学-B 序列的与和
题目描述
WY是一个序列大师,他喜欢研究一些和序列相关的操作。时间长了,WY对某一些特定的序列产生了感情,换句话说,WY喜欢和这些特定的序列打交道。比如说WY最近就迷上了这样一类序列:
-
我们规定序列的与和定义为序列中所有元素按位与得到的结果。
-
如序列 [1,2,3] :其与和结果为1&2&3=0.
-
若一个序列与和的结果,其二进制表示形式下包含 k 个 1 ,WY则会认为这是他喜欢的序列
现在WY的手里有一个序列了,他想知道,这个的序列的非空子序列中有多少个他喜欢的序列。由于WY已经非常熟悉这类序列了,所以他想考考你,看看你是否能解决这个问题。
子序列定义为:从原序列中去除几个(可以为零个)元素后得到的序列。
( 1 ≤ n ≤ 20 ) ( 0 ≤ k ≤ 20 ) ( 0 ≤ a i ≤ 2 64 − 1 ) (1 \le n \le 20 )(0 \le k \le 20 )(0 \le a_i \le 2^{64}-1 ) (1≤n≤20)(0≤k≤20)(0≤ai≤264−1)
思路
首先它需要考虑所有的子序列 (至少含有一个数) 而n的范围只有20所以我们可以用二进制01表示是否取。复杂度也只有
O
(
2
n
∗
n
)
O(2^n*n)
O(2n∗n) 只需要将外层的循环中判断该位是否进子序列再与和运算即可
(说白了就是暴力)
上代码
#include <bits/stdc++.h>
using namespace std;
#define ll long long
int n,k;
ll a[25];
int sum=0;
int main()
{
scanf("%d%d",&n,&k);
for(int i=1;i<=n;i++)
scanf("%lld",&a[i]);
int kp=(1<<n);//每一个数是否取
for(int i=1;i<kp;i++)//不考虑空串所以i从1开始
{
ll l,f=0;
for(int j=1;j<=n;j++)
{
if((i>>(j-1))&1)//判断第j个数是否进此时的子序列
{
if(!f) {l=a[j];f=1;}
else l&=a[j];
}
}
int cnt=0;
while(l) {
l-=(l&-l);//删除01中最后一个1
cnt++;//统计1的个数
}
if(cnt==k)
{
sum++;
}
}
cout<<sum;
}