[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 很自然地有一个 ...
随机推荐
- 《Python学习手册 第五版》 -第5章 数值类型
本章是承接第四章整体说明之后,将对”数值类型“展开详细的说明 数值类型这一章主要通过一下几个内容来讲解: 1.数值类型有哪些? 2.表达式运算符:有哪些?有什么规范? 3.数值的显示格式 接下来,从第 ...
- 使用IDEA详解Spring中依赖注入的类型(上)
使用IDEA详解Spring中依赖注入的类型(上) 在Spring中实现IoC容器的方法是依赖注入,依赖注入的作用是在使用Spring框架创建对象时动态地将其所依赖的对象(例如属性值)注入Bean组件 ...
- 在yum安装lamp的环境下安装coreseek以及php的sphinx扩展
首先说明下,之前的lamp环境用yum快速安装的现在装一个coreseek学习学习: 在安装前建议安装下这四个东西,以免后续安装报错 $ curl -O -L http://mirrors.kerne ...
- ELF文件之二——使用链接脚本
main.c int main() { ; } 编译:sparc-elf-gcc.exe -c main.c -o main.o 链接:sparc-elf-ld.exe main.o -nostart ...
- 解决Python2.7的UnicodeEncodeError: 'ascii' codec can't encode异常错误
UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-2: ordinal not in range(128) ...
- Arm开发板+Qt学习之路-析构函数和对话框一起时
先记录一下代码 一:先将指针释放掉,在显示对话框 void MainWindow::canResponseError(SendCanMsgThread *sendCanMsgThread ){ std ...
- 西门子S7comm协议解析 —— 利用Wireshark对报文逐字节进行解析详细解析S7comm所含功能码以及UserData功能
又一次成为懒蛋了,标题就这么改了改又是一篇新文章. 网上也有很多S7comm协议的解析,但还是如同我上一篇一样我只是做报文的解析对于S7comm的原理并进行阐述. 有些地方有错误的地方尽请大家指出,共 ...
- linux文件系统相关命令(df/du/fsck/dumpe2fs)
一.文件系统查看命令df 格式 df [选项] [挂载点] 选项 名称 作用 -a 显示所有的文件系统信息,包括特殊文件系统,如/proc,/sysfs -h 使用习惯单位显示容量,如KB,MB或GB ...
- 刷题85. Maximal Rectangle
一.题目说明 题目,85. Maximal Rectangle,计算只包含1的最大矩阵的面积.难度是Hard! 二.我的解答 看到这个题目,我首先想到的是dp,用dp[i][j]表示第i行第j列元素向 ...
- AndroidStudio更新时报错:Connection Error,Temp directory inside installation
场景 在将Android Studio的 .AndroidStudio目录修改为别的目录后,打开AS,提示更新,点击更新后提示: Connection Error,Temp directory ins ...