FWT+高维前缀和:Gym - 103202M

本文搬运自本人高中时期CSDN博客,若图片加载不出来,可到原文查看:https://blog.csdn.net/zhangtingxiqwq/article/details/134749229

https://vj.imken.moe/contest/597216#problem/F

考虑两个人的集合分别为 i,ji,j ,那么我们令 f(ij)++f(i\otimes j)++ ,其中 f(s)f(s) 表示两个人不同集合 恰好ss ,显然 f(s)f(s) 可以FWT求。

假设 g(t)g(t) 表示选集合为 tt 有多少个不同的对数,显然有 g(t)=s&jf(s)=n(n1)2sUtf(s)g(t)=\sum_{s\& j\neq \empty}f(s)=\frac {n(n-1)}2-\sum_{s\subseteq U-t}f(s) ,因此我们对 ff 做一遍高维前缀和即可。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
#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;
}