题目链接:https://codeforces.com/gym/103202/problem/M
一句话题意:求满足 $$sumlimits_{i=1}^n sumlimits_{j=i+1}^{n}[a_i oplus a_j cap S>0] >= k$$ 的集合 (S) 的数量
将问题分为两部分,第一步,求出 $$sumlimits_{i=1}^{n} sumlimits_{j=i+1}^{n} a_i oplus a_j = S$$ 的 ((i,j))对的数量
令 (num[i]) 表示 (i) 的数量,答案即为 (F[s] = frac{1}{2}sumlimits_{ioplus j = S}num[i]*num[j]),(fwt) 即可
第二步,如果 (G[S] = sumlimits_{Tcap S eq 0} F[T] >= k),则 (S) 有贡献,容斥一下变为 (G[S] = frac{n imes n}{2} - sumlimits_{Tcap S = 0} F[T]),即求 (S) 补集的子集和,高维前缀和可在 (O(m2^m)) 内求出
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 200010;
const int maxm = (1 << 20) + 10;
int n, m, N; ll k;
ll a[maxm], b[maxm], g[maxn];
void fwt(ll *f,int type){
for(int i=1;i<N;i<<=1){
for(int j=0;j<N;j+=(i<<1)){
for(int k=0;k<i;k++){
ll p=f[j+k],q=f[i+j+k];
if(type==1) f[j+k]=p+q,f[i+j+k]=p-q;
else f[j+k]=(p+q)/2,f[i+j+k]=(p-q)/2;
}
}
}
}
char s[maxn];
ll read(){ ll s = 0, f = 1; char ch = getchar(); while(ch < '0' || ch > '9'){ if(ch == '-') f = -1; ch = getchar(); } while(ch >= '0' && ch <= '9'){ s = s * 10 + ch - '0'; ch = getchar(); } return s * f; }
int main(){
scanf("%d%d%lld", &n, &m, &k);
N = (1 << m);
int num = 0;
for(int i = 1 ; i <= n ; ++i){
scanf("%s", s+1);
int len = strlen(s+1);
num = 0;
for(int j = 1 ; j <= len ; ++j){
num = (num<<1) + (s[j] == 'A' ? 1 : 0);
}
++a[num];
}
for(int i = 0 ; i < N ; ++i) b[i] = a[i];
fwt(a, 1), fwt(b, 1);
for(int i = 0 ; i < N ; ++i) a[i] = a[i] * b[i];
fwt(a, -1);
a[0] -= n;
for(int i = 0 ; i < N ; ++i) a[i] /= 2;
for(int j = 0 ; j < m ; ++j){
for(int i = 0 ; i < (1 << m) ; ++i){
if((i>>j) & 1) {
a[i] = a[i] + a[i^(1<<j)];
}
}
}
int ans = 0;
ll lim = 1ll*n*(n-1)/2-k;
int all = (1 << m) - 1;
for(int i = 0 ; i < N ; ++i){
if(a[all^i] <= lim) ++ans;
}
printf("%d
", ans);
return 0;
}