FWT+高维前缀和:Gym - 103202M
https://vj.imken.moe/contest/597216#problem/F
考虑两个人的集合分别为 i , j i,j i,j,那么我们令 f ( i ⊗ j ) + + f(i\otimes j)++ f(i⊗j)++,其中 f ( s ) f(s) f(s) 表示两个人不同集合恰好为 s s s,显然 f ( s ) f(s) f(s) 可以FWT求。
假设 g ( t ) g(t) g(t) 表示选集合为 t t t 有多少个不同的对数,显然有 g ( t ) = ∑ s & j ≠ ∅ f ( s ) = n ( n − 1 ) 2 − ∑ s ⊆ U − t f ( s ) g(t)=\sum_{s\& j\neq \empty}f(s)=\frac {n(n-1)}2-\sum_{s\subseteq U-t}f(s) g(t)=∑s&j=∅f(s)=2n(n−1)−∑s⊆U−tf(s),因此我们对 f f f 做一遍高维前缀和即可。
#include<bits/stdc++.h>
using namespace std;
#ifdef LOCAL
#define debug(...) fprintf(stdout, ##__VA_ARGS__)
#else
#define debug(...) void(0)
#endif
#define int long long
inline int read(){int x=0,f=1;char ch=getchar(); while(ch<'0'||
ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch>='0'&&ch<='9'){
x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}return x*f;}
#define Z(x) (x)*(x)
#define pb push_back
#define fi first
#define se second
//srand(time(0));
#define N 2000010
//#define M
//#define mo
int n, m, i, j, k, T;
int g[N], a[N], ans;
char str[N];
struct FWT {
int f[N], n, o, i, j, k;
void XOR(int x) {
for(k=1, o=2; o<=n; o<<=1, k<<=1) {
for(i=0; i<n; i+=o)
for(j=0; j<k; ++j) {
f[i+j]+=f[i+j+k];
f[i+j+k]=f[i+j]-2*f[i+j+k];
if(x==-1) f[i+j]/=2, f[i+j+k]/=2;
}
}
}
void Mul() {
for(i=0; i<n; ++i) f[i]*=f[i];
}
void work(int p) {
f[0]-=p;
for(i=0; i<n; ++i) f[i]/=2;
}
}fwt;
signed main()
{
#ifdef LOCAL
freopen("in.txt", "r", stdin);
freopen("out.txt", "w", stdout);
#endif
// T=read();
// while(T--) {
//
// }
n=read(); m=read(); k=read();
fwt.n=(1<<m);
for(i=1; i<=n; ++i) {
scanf("%s", str+1);
for(j=1; j<=m; ++j) if(str[j]=='B') a[i]|=(1<<j-1);
fwt.f[a[i]]++;
}
fwt.XOR(1); fwt.Mul(); fwt.XOR(-1); fwt.work(n);
for(i=0; i<(1<<m); ++i) g[i]=fwt.f[i];
for(i=0; i<(1<<m); ++i) debug("%lld ", g[i]); debug("\n");
for(j=0; j<m; ++j)
for(i=0; i<(1<<m); ++i)
if(i&(1<<j)) g[i]+=g[i-(1<<j)];
for(i=0; i<(1<<m); ++i) debug("%lld ", g[i]); debug("\n");
for(i=0; i<(1<<m); ++i) if(i<(1<<m)-i) swap(g[i], g[(1<<m)-1-i]);
for(i=0; i<(1<<m); ++i) debug("%lld ", g[i]); debug("\n");
for(i=1; i<(1<<m); ++i) g[i]=n*(n-1)/2-g[i];
for(i=1; i<(1<<m); ++i) if(g[i]>=k) ++ans;
printf("%lld", ans);
return 0;
}