Problem:
Score : 800 points

Problem Statement

Given are N pairwise distinct non-negative integers A_1,A_2,\ldots,A_N.
Find the number of ways to choose a set of between 1 and K numbers (inclusive) from the given numbers so that the following two conditions are satisfied:

The bitwise AND of the chosen numbers is S.

The bitwise OR of the chosen numbers is T.

Constraints

1 \leq N \leq 50

1 \leq K \leq N

0 \leq A_i < 2^{18}

0 \leq S < 2^{18}

0 \leq T < 2^{18}

A_i \neq A_j (1 \leq i < j \leq N)

Input

Input is given from Standard Input in the following format:

N K S T
A_1 A_2 ... A_N

Output

Print the answer.

Sample Input 1

3 3 0 3
1 2 3

Sample Output 1

2

The conditions are satisfied when we choose \{1,2\} or \{1,2,3\}.

Sample Input 2

5 3 1 7
3 4 9 1 5

Sample Output 2

2

Sample Input 3

5 4 0 15
3 4 9 1 5

Sample Output 3

3

Solution in C++ (GCC 9.2.1) (judge verdict: Accepted)

/*    特徴    */
// 包除原理

/*    教訓    */
// nCkは油断するとすぐオーバーフローする

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

using ll = long long;
using ld  = long double;
using pint = pair<int, int>;
using pll = pair<ll, ll>;
using pld = pair<ld, ld>;
const int INF=1e9+7;
const ll LINF=9223372036854775807;
const ll MOD=1e9+7;
const ld PI=acos(-1);
const ld EPS = 1e-10; //微調整用（EPSより小さいと0と判定など）

int ii() { int x; if (scanf("%d", &x)==1) return x; else return 0; }
long long il() { long long x; if (scanf("%lld", &x)==1) return x; else return 0; }
string is() { string x; cin >> x; return x; }
char ic() { char x; cin >> x; return x; }
void oi(int x) { printf("%d ", x); }
void ol(long long x) { printf("%lld ", x); }
void od_nosp(double x) { printf("%.15f", x); } // 古い問題用
void od(double x) { printf("%.15f ", x); }
// long doubleで受け取り、fをLfなどに変えて出力すると、変な数値が出る
// それをなんとかするには独自の出力を作らなければならなそう
void os(const string &s) { printf("%s ", s.c_str()); }
void oc(const char &c) { printf("%c ", c); }
#define o_map(v){cerr << #v << endl; for(const auto& xxx: v){cout << xxx.first << " " << xxx.second << "\n";}} //動作未確認
void br() { putchar('\n'); }

#define gcd __gcd //llは受け取らない C++17~のgcdと違うので注意
int lcm(int a, int b){return a / gcd(a, b) * b;}
#define begin_end(a) a.begin(),a.end() //sort(begin_end(vec));
#define REP(i,m,n) for(ll i=(ll)(m) ; i < (ll) (n) ; i++ )
#define rep(i,n) REP(i,0,n)
#define m_p(a,b) make_pair(a,b)
#define SORT_UNIQUE(c) (sort(c.begin(),c.end()), c.resize(distance(c.begin(),unique(c.begin(),c.end()))))
#define GET_POS(c,x) (lower_bound(c.begin(),c.end(),x)-c.begin())
#define p_b push_back
#define SZ(x) ((int)(x).size) //size()がunsignedなのでエラー避けに

//4近傍（上下左右） rep(i, 2) にすると右・下だけに進む
vector<int> dx_4 = {1, 0, -1, 0};
vector<int> dy_4 = {0, 1, 0, -1};

// coutによるpairの出力（空白区切り）
template<typename T1, typename T2> ostream& operator<<(ostream& s, const pair<T1, T2>& p) {return s << "(" << p.first << " " << p.second << ")";}
// coutによるvectorの出力（空白区切り）
template<typename T> ostream& operator<<(ostream& s, const vector<T>& v) {
  int len = v.size();
  for (int i = 0; i < len; ++i) {
    s << v[i]; if (i < len - 1) s << " "; //"\t"に変えるとTabで見やすく区切る
  }
  return s;
}
// coutによる多次元vectorの出力（空白区切り）
template<typename T> ostream& operator<<(ostream& s, const vector< vector<T> >& vv) {
  int len = vv.size();
  for (int i = 0; i < len; ++i) {
    s << vv[i] << endl;
  }
  return s;
}

//最大値、最小値の更新。更新したor等しければtrueを返す
template<typename T>
bool chmax(T& a, T b){return (a = max(a, b)) == b;}
template<typename T>
bool chmin(T& a, T b){return (a = min(a, b)) == b;}

// -------- template end - //


// - library ------------- //

ll llpow(ll a, ll b){
    if(b == 0){
        return 1;
    }
    ll ans = llpow(a, b / 2);
    ans = ans * ans; // % MOD; (MODつけたい場合のコピー用)
    if(b % 2 == 1){
        ans = ans * a; // % MOD; (MODつけたい場合のコピー用)
    }
    return ans;
}

// --------- library end - //


int main(){

  // 普通にnCkを計算するとオーバーフローするので、パスカルの三角形を利用
  ll n_limit = 50; //!! nの最大値を設定 !!
  vector<ll> CmbsVec( ( 2 + n_limit ) * ( 1 + n_limit ) / 2 );
  //nCkへのアクセスは .at( ( n + 1 ) * n / 2 + k )
  //n-1まで（1段上）の要素の総数が ( n + 1 ) * n / 2 なので、その次の段のk+1個目を0-indexed (つまり-1)に直すと、この式に
  
  //nC0, nCnは全て1に
  rep(i, n_limit+1){  //n : 0〜n_limitについて
    CmbsVec.at( ( i + 1 ) * i / 2 + 0 ) = 1;  //nC0
    CmbsVec.at( ( i + 1 ) * i / 2 + i ) = 1; //nCn
  }
  
  //n C 1〜n-1を前計算 nは2からスタート
  REP(n, 2, n_limit + 1){ //nは2〜n_limitまで全て
    REP(k, 1, n){ //kは1〜n-1
      // nCk = n-1Ck-1 + n-1Ck を利用している
      // n+1Ck = nCk + n-1Ck-1 と考えてもいい
      CmbsVec.at( ( n + 1 ) * n / 2 + k ) = CmbsVec.at( n * ( n - 1) / 2 + k - 1 ) + CmbsVec.at( n * ( n - 1 ) / 2 + k );
    }
  }
  
  // nCkを返すlambda式 Comb(n, k)で使う
  auto comb = [&] (ll n, ll k) -> ll {
    if (n==0 && k==0) return 1;
    else if (n < k) return 0;
    return CmbsVec.at( ( n + 1 ) * n / 2 + k );
  };
  

  // ここから本題

  ll max_digit = 18;

  ll N, K, S, T;
  cin >> N >> K >> S >> T;

  vector<ll> As(N);
  rep(i, N){
    As[i] = il();
  }

  // S=Tのコーナーケースを処理
  if (S==T){
    // S=T=Ai となるようなAiがあれば答えは1, なければ0
    if (find(As.begin(), As.end(), S) != As.end()){
      cout << 1 << endl;
      return 0;
    }
    else{
      cout << 0 << endl;
      return 0;
    }
  }

  // 各Ai のうち、使えないやつを弾き出す

  rep(d, max_digit){
    // 0桁目から17桁目まで、右端から18bit分見ていく
    vector<ll> tmp_as;
    if ((S & (1<<d)) && !(T & (1<<d))){
      // これがあったら、そもそも無理
      cout << 0 << endl;
      return 0;
    }
    else if (!(S & (1<<d)) && !(T & (1<<d))){
      // i桁目が1であるようなAiを弾いて、それ以外を使う
      rep(i, As.size()){
        if (!(As[i] & (1<<d))) tmp_as.push_back(As[i]);
      }
    }
    else if ((S & (1<<d)) && (T & (1<<d))){
      // i桁目が0であるようなAiを弾いて、それ以外を使う
      rep(i, As.size()){
        if ((As[i] & (1<<d))) tmp_as.push_back(As[i]);
      }
    }
    else{
      // bss[d] == 1 && bst[d] == 0 ならはじき出さない
      // つまり、Asは変化させない
      continue;
    }
    // Asを更新（はじき出されたものが減る）
    As = tmp_as;
  }

  /* 
    ここまでで、As の整理とコーナーケース（答え:0のパターン）の処理が終わった
    具体的には、
    S,T=1,0 のbitは存在しない（もし1つでも存在すれば答えは0で終了済）
    S,T=0,0 となっている桁のbitは、0 のもの以外残っていない
    S,T=1,1 となっている桁のbitは、1 のもの以外残っていない
  */

  // 上記より、S,T=0,1以外の桁は無視していいことになったので、削除してしまう
  // 上の桁から見ていく
  for (ll d = max_digit-1; d >= 0; --d){
    if ( !( !(S&(1<<d)) && (T&(1<<d)) ) ){
      // ST=01でなければ、その桁を削除
      max_digit--;
      rep(i, As.size()) As[i] = As[i]/(1<<(d+1))*(1<<(d)) + As[i]%(1<<d);
      S = S/(1<<(d+1))*(1<<(d)) + S%(1<<d);
      T = T/(1<<(d+1))*(1<<(d)) + T%(1<<d);
    }
  }

  // あとは、各mask毎にAiをグループ分けする
  // グループ分けとは？
  // --> 各maskのbitが立っている桁（包除原理による場合の数の計算において、Bを「どんな組合せでもいい」、Aを「全部0 もしくは 全部1 となる組合せ」とした場合の、Aとしたい桁）については、同じbitの立ち方をしているAiを組合せないと、Aパターンにならない（Aにしたいある桁について、0と1が混在してしまう）ため、同じbitの立ち方をしているAiの数を数える
  // ＜数え方＞ Vector<map<ll, ll> Eg[mask] := map<key:bitの立ち方, value:その立ち方をしているAiの数>

  ll two_tpo = llpow(2, max_digit); // 2^(残り桁数)

  // Eg[mask:0~2^残り桁数-1] := map<key:Ai&mask, value:数>
  vector<map<ll, ll> > Eg(two_tpo, map<ll, ll>());

  // Eg（maskごとに、各グループに属するAiが何個ずつあるか）の計算
  rep(mask, two_tpo){
    for (ll a : As){
      Eg[mask][a & mask]++;
    }
  }

  // 答えを求める
  ll ans = 0;
  
  // f[m] = Σ(k:1~K)mCk を m:0~N について前計算
  vector<ll> f(N+1, 0);
  REP(k, 1, K+1){
    rep(m, N+1){
      f[m] += comb(m, k); // mCk
    }
  }


  rep(mask, two_tpo){
    ll popcount = __builtin_popcountll(mask); // mask の立っているbit数
    for (pair<ll, ll> each_keyandvalue : Eg[mask]){
      ll value = each_keyandvalue.second; // mask グループに属するAiの数

      // 包除原理により、popcount奇数の場合は-、popcount偶数の場合は+
      if (popcount%2 == 1){
        ans -= f[value];
      } 
      else{
        ans += f[value];
      }
    }
  }

  cout << ans << endl;
  
}