FWT+高维前缀和:Gym - 103202M
本文搬运自本人高中时期CSDN博客,若图片加载不出来,可到原文查看:https://blog.csdn.net/zhangtingxiqwq/article/details/134749229
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 ) = 2 n ( n − 1 ) − ∑ s ⊆ U − t f ( s ) ,因此我们对 f f f 做一遍高维前缀和即可。
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 #define N 2000010 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 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 ; }