[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 很自然地有一个 ...
随机推荐
- 【Bullet引擎】Bullet物理引擎简单说明
说明 Bullet是一款开源的物理模拟计算引擎,包括刚体.柔体.弹性体等,是世界三大物理模拟引擎之一(包括Havok和PhysX),被广泛应用于游戏开发(GTA5等)和电影(2012等)制作中. Bu ...
- sqlserver附加数据库时出错。有关详细信息,请单击“消息”列中的超链接
在SqlServer中附加数据库时,有时会发生下面的错误. 解决 :可能的问题是放置附加数据库的文件夹的权限问题.如下解决.点击放置附加数据库的文件夹-->右键-->属性 权限要设置为完全 ...
- VFP的13个SPT函数
Visual FoxPro 中内置了13个以SQL开头的函数,我们把它们称为SPT函数.就是这13个函数完成了Visual FoxPro的所有的SQL Pass Though功能.从功能上看,我们可以 ...
- ospfv3 lsa database
https://www.networkfuntimes.com/ospfv3-the-new-lsa-types-in-ipv6-ospf/ WHY DID THEY CHANGE THE LSAs ...
- 学习CSS之如何改变CSS伪元素的样式
一.CSS伪元素 CSS 伪元素用于向某些选择器设置特殊效果. 伪元素的用法如下: selector:pseudo-element {property:value;} CSS 类也可以和伪元素搭配使用 ...
- getElementsByName和getElementById获取控件
js对控件的操作通常使用getElementsByName或getElementById来获取不同的控件进行操作 getElementsByName() 得到的是一个array, 不能直接设value ...
- git 指令笔记
狂躁,太狂躁!!赶上过年,赶上自己的懒癌,12月底就学完的教程直到今天才整理笔记,中途沉默在游戏中..... 只给出Windows下git指令操作,推荐大家去廖雪峰前辈那里学习(百度搜索:廖雪峰的官方 ...
- Linux运维---1.磁盘相关知识
一 磁盘物理结构 (1) 盘片:硬盘的盘体由多个盘片叠在一起构成. 在硬盘出厂时,由硬盘生产商完成了低级格式化(物理格式化),作用是将空白的盘片(Platter)划分为一个个同圆心.不同半径的磁道(T ...
- Apache Solr JMX服务 RCE 漏洞复现
Apache Solr JMX服务 RCE 漏洞复现 ps:Apache Solr8.2.0下载有点慢,需要的话评论加好友我私发你 0X00漏洞简介 该漏洞源于默认配置文件solr.in.sh中的EN ...
- RedHat7安装NetCore环境并发布网站
RedHat7安装NetCore环境并发布网站 1.注册Microsoft签名密钥并添加Microsoft产品提要,每台机器只需注册一次 执行下面的命令即可 rpm -Uvh https://pack ...