当前位置: 首页 > article >正文

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(ij)++,其中 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(n1)sUtf(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;
}



http://www.kler.cn/a/153648.html

相关文章:

  • scrapy的建模及管道的使用
  • Spring Boot 3.2 新特性之 JdbcClient
  • 【Linux】awk 使用
  • 最小栈,力扣
  • FAT32文件系统详解
  • 【论文阅读】ActiveNeRF:通过不确定性估计候选新视图
  • 第三节:提供者、消费者、Eureka
  • 天鹅湖国家旅游度假区 | 展柜OLED透明屏:创新展示提升互动体验
  • 聚观早报 |国行PS5轻薄版开售;岚图汽车11月交付7006辆
  • C语言-预处理与库
  • 【Node.js】笔记整理 1 - 基础知识
  • [笔记]dubbo发送接收
  • 【嵌入式Linux程序开发综合实验】-1(附流程图) | ARM开发板 | 测试“Hello World” | Makefile文件 | 实现加法相加
  • 【Go】protobuf介绍及安装
  • Hdoop学习笔记(HDP)-Part.11 安装Kerberos
  • Hdoop学习笔记(HDP)-Part.12 安装HDFS
  • RPA机器人如何解决非银企直联网银账户的数据自动采集?
  • mediapipe+opencv实现保存图像中的人脸,抹去其他信息
  • virtualbox中windows11开机自动登录设置
  • UI自动化Selenium OCR库:ddddocr识别验证码