tokiomarine2020 E O(rand)【容斥】
给定 \(n\) 元可重集合 \(A\) 和正整数 \(k,S,T\),求 \(A\) 有多少个 \(\le k\) 元子集 \(B\) 的按位与为 \(S\),按位或为 \(T\)。
\(k\le n\le 50,A\subseteq[0,2^{18})\)。
显然可以转化为 \(S=0,T=2^l-1\) 的情况,其中 \(l=\text{popcount}(S\oplus T)\)。
条件即为所有位都至少出现一次但不全出现。
容斥一下,钦定一些位要么全出现要么全不出现,设这些位是 \(x\),则有 \(\forall y\in B,x\&y\) 都相等。
直接暴力,时间复杂度 \(O(n2^l)\)。
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 53, M = 1<<18;
template<typename T>
void read(T &x){
int ch = getchar(); x = 0;
for(;ch < '0' || ch > '9';ch = getchar());
for(;ch >= '0' && ch <= '9';ch = getchar()) x = x * 10 + ch - '0';
} int _n, n, k, S, T, a[N], c[M]; LL F[N], C[N][N];
int main(){
read(_n); read(k); read(S); read(T);
if((S | T) != T) return puts("0"), 0;
while(_n --){
int x; read(x);
if(S == (S & x) && T == (T | x)) a[++n] = x;
} for(int i = 0;i <= n;++ i)
for(int j = *C[i] = 1;j <= i && j <= k;++ j)
F[i] += C[i][j] = C[i-1][j] + C[i-1][j-1];
int _ = S ^ T; LL ans = F[n];
for(int u = _;u;u = u-1&_){
LL res = 0;
for(int i = 1;i <= n;++ i) ++c[a[i]&u];
for(int i = 1;i <= n;++ i){
int &tmp = c[a[i]&u];
res += F[tmp]; tmp = 0;
} ans += __builtin_popcount(u) & 1 ? -res : res;
} printf("%lld\n", ans);
}