[CF662C Binary Table][状压+FWT]
一道 FWT 的板子…比较难想就是了
有一个 \(n\) 行 \(m\) 列的表格,每个元素都是 \(0/1\),每次操作可以选择一行或一列,把 \(0/1\) 翻转,即把 \(0\) 换为 \(1\) ,把 \(1\) 换为 \(0\) 。请问经过若干次操作后,表格中最少有多少个 \(1\)。
\(1 \leq n \leq 20\)
\(1 \leq m \leq 10^5\)
先说说 FWT 干嘛的吧
\(F_k = \sum_{i \oplus j=k} a_i * b_j\)
首先呢 这题其实是有个暴力做法的
(认为是 n 行 m 列的一个矩阵)
复杂度大概是 \(2^n * m\)
就是你暴力搞 \(n\) 枚举每个状态复杂度自然是 \(2^n\) 的 然后你每次搜索/状压 搞到一个地方之后 算当前列的 0/1 个数取 \(min\) 因为列是可以翻转的…
暴力做法 没了 但是这种做法在CF里并不给分所以没啥用
但是对以下的做题有大用处
你可以把最开始矩阵 \(m\) 列状压 \(n\) 这样就成了个二进制
然后 \(a\) 数组计数
\(b_i\) 数组表示 i 的 0的个数,1的个数取 min
然后如果对矩阵变换也可以表示成状态 那么就是最开始的状态 \(i \oplus k\)
然而可以发现
\(i\oplus j=k\) 可以变成 \(i\oplus k=j\)
然后 FWT 还是可以用的
直接跑板子
因为你最开始变换的是 \(k\) 最后要枚举取个 \(min\) 求最优解
这题没了…
#include <bits/stdc++.h>
#define int long long
#define rep(a , b , c) for(int a = b ; a <= c ; ++ a)
#define Rep(a , b , c) for(int a = b ; a >= c ; -- a)
#define go(u) for(int i = G.head[u] , v = G.to[i] , w = G.dis[i] ; i ; v = G.to[i = G.nxt[i]] , w = G.dis[i])
using namespace std ;
using ll = long long ;
using pii = pair < int , int > ;
using vi = vector < int > ;
int read() {
int x = 0 ; bool f = 1 ; char c = getchar() ;
while(c < 48 || c > 57) { if(c == '-') f = 0 ; c = getchar() ; }
while(c > 47 && c < 58) { x = (x << 1) + (x << 3) + (c & 15) ; c = getchar() ; }
return f ? x : -x ;
}
template <class T> void print(T x , char c = '\n') {
static char st[100] ; int stp = 0 ;
if(! x) { putchar('0') ; }
if(x < 0) { x = -x ; putchar('-') ; }
while(x) { st[++ stp] = x % 10 ^ 48 ; x /= 10 ; }
while(stp) { putchar(st[stp --]) ; } putchar(c) ;
}
template <class T> void cmax(T & x , T y) { x < y ? x = y : 0 ; }
template <class T> void cmin(T & x , T y) { x > y ? x = y : 0 ; }
const int _N = 1e6 + 10 ;
struct Group {
int head[_N] , nxt[_N << 1] , to[_N] , dis[_N] , cnt = 1 ;
Group () { memset(head , 0 , sizeof(head)) ; }
void add(int u , int v , int w = 1) { nxt[++ cnt] = head[u] ; to[cnt] = v ; dis[cnt] = w ; head[u] = cnt ; }
} ;
const int N = 1 << 21 ;
typedef int arr[N] ;
int n , m ;
void FWT(int * a) {
for(int d = 1 ; d <= n - 1 ; d <<= 1) {
for(int i = 0 ; i <= n - 1 ; i += (d << 1))
rep(j , 0 , d - 1) {
int x = a[i + j] , y = a[i + j + d] ;
a[i + j] = x + y ;
a[i + j + d] = x - y ;
}
}
}
void IFWT(int * a) {
for(int d = 1 ; d <= n - 1 ; d <<= 1) {
for(int i = 0 ; i <= n - 1 ; i += (d << 1))
rep(j , 0 , d - 1) {
int x = a[i + j] , y = a[i + j + d] ;
a[i + j] = x + y >> 1 ;
a[i + j + d] = x - y >> 1 ;
}
}
}
int digit() {
char c = getchar() ;
while(! (c >= 48 && c <= 57)) c = getchar() ;
if(c == 49) return 1 ;
return 0 ;
}
arr a , b , f , g , cnt ;
signed main() {
n = read() ; m = read() ;
rep(i , 0 , n - 1) {
rep(j , 0 , m - 1) {
if(digit())
g[j] |= (1 << i) ;
}
}
rep(i , 0 , m - 1) a[g[i]] ++ ;
int nn = n ;
n = 1 << n ;
rep(i , 1 , n - 1) cnt[i] = cnt[i >> 1] + (i & 1) ;
rep(i , 0 , n - 1) b[i] = min(cnt[i] , nn - cnt[i]) ;
FWT(a) ; FWT(b) ;
rep(i , 0 , n - 1) a[i] *= b[i] ;
IFWT(a) ;
ll ans = 1e18 ;
rep(i , 0 , n - 1) ans = min(ans , a[i]) ;
print(ans) ;
return 0 ;
}
[CF662C Binary Table][状压+FWT]的更多相关文章
- Codeforces.662C.Binary Table(状压 FWT)
题目链接 \(Description\) 给定一个\(n\times m\)的\(01\)矩阵,你可以选择一些行和一些列并将其中所有的\(01\)反转.求操作后最少剩下多少个\(1\). \(n\le ...
- CF662C Binary Table【FWT】
CF662C Binary Table 题意: 给出一个\(n\times m\)的\(01\)矩阵,每次可以反转一行或者一列,问经过若干次反转之后,最少有多少个\(1\) \(n\le 20, m\ ...
- CF662C Binary Table FWT
传送门 \(N \leq 20\)很小诶 一个暴力的思路是枚举行的翻转状态然后在列上贪心 复杂度为\(O(2^NM)\)显然过不去 考虑到可能有若干列的初始状态是一样的,那么在任意反转之后他们贪心的策 ...
- CF662C Binary Table (快速沃尔什变换FWT)
题面 题解 我们会发现,如果单独的一列或一行,它的答案是O1确定的,如果确定了每一行是否变换,那么最后的答案也就简单了许多, 如果确定了行的变换状压下来是x(即x的i位表示第i行是否变换,理解就行), ...
- CF662C Binary Table 【状压 + FWT】
题目链接 CF662C 题解 行比较少,容易想到将每一列的状态压缩 在行操作固定的情况下,容易发现每一列的操作就是翻转\(0\)和\(1\),要取最小方案,方案唯一 所以我们只需求出每一种操作的答案 ...
- CF662C Binary Table 枚举 FWT
题面 洛谷题面 (虽然洛谷最近有点慢) 题解 观察到行列的数据范围相差悬殊,而且行的数量仅有20,完全可以支持枚举,因此我们考虑枚举哪些行会翻转. 对于第i列,我们将它代表的01串提取出来,表示为\( ...
- CF662C Binary Table (FWT板题)
复习了一发FWT,发现还挺简单的... 没时间写了,就放一个博客吧:Great_Influence 的博客 注意这一句ans[i]=∑j⊗k=if[j]∗dp[k]ans[i]= ∑_{j⊗k=i} ...
- [CF662C] Binary Table(FWT)
题意: https://www.cnblogs.com/cjyyb/p/9065801.html 题解:
- [CF662C]Binary Table
luogu 题意 你有一个\(n*m\)的\(01\)矩阵.你可以把任意一行或者一列的\(01\)取反.求矩阵中最少的\(1\)的数量. \(n\le20,m\le10^5\) sol 很自然地有一个 ...
随机推荐
- 15-Git使用语法
Git命令 版本库的创建 方法一:使用git bash 1. 在当当前要加创建版本库的文件夹右键使用GitBash 创建仓库执行命令: $ git init 方法二:使用TortoiseGit 2. ...
- 20200220--python学习第13天
今日内容 作业题(21题) 推导式 装饰器 模块[可选] 内容回顾 1.函数 a.参数 def func(a1,a2):pass def func(a1,a2=None):pass 默认参数推荐使用不 ...
- 获取本机网卡ip地址
import sys, os import socket, struct, fcntl import six import psutil def get_ip(iface="enp0s3&q ...
- 1 Nginx + 12 Tomcat +2DB 实现2个程序负载均衡
根据真实生产环境 总结. 硬件:共计5台服务器 1台负载windows.2台业务windows.2台数据库linux 业务:运行两个程序,两个数据库 具体:63服务器安装 Nginx 做负载 :61 ...
- LVM知识梳理
1 LVM介绍 LVM即logical volume manager逻辑卷管理,其主要特点是:可以动态地扩大和缩小分区大小,但前提是分区的文件系统必须是LVM格式的,lvm的实现需要安装lvm2软件包 ...
- 利用预测分析改进欠款催收策略,控制欺诈风险和信贷风险—— Altair Knowledge Studio 预测分析和机器学习
前提摘要 在数字经济新时代,金融服务主管正在寻求方法去细分他们的产品和市场,保持与客户的联系,寻找能够推动增长和收入的新市场,并利用可以增加优势和降低风险的新技术. 在拥有了众多可用数据之后,金融机构 ...
- NodeJs-promise和async_await语法
Callback hell回调地域 当我们以同步的方式编写耗时的代码,那么就会阻塞JS的单线程,造成CPU一直等待IO完成才去执行后面的代码. 而CPU的执行速度是远远大于硬盘IO速度的,这样等待只会 ...
- redis中hash数据类型
remoteSelf:1>hset website google "www.google.com" "1" remoteSelf:1>hget we ...
- Android进程调度之adj算法
copy from : http://gityuan.com/2016/08/07/android-adj/ 一.概述 提到进程调度,可能大家首先想到的是Linux cpu调度算法,进程优先级之类概念 ...
- Leetcode:235. 二叉搜索树的最近公共祖先
Leetcode:235. 二叉搜索树的最近公共祖先 Leetcode:235. 二叉搜索树的最近公共祖先 Talk is cheap . Show me the code . /** * Defin ...