CF662C Binary Table

一道 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]的更多相关文章

  1. Codeforces.662C.Binary Table(状压 FWT)

    题目链接 \(Description\) 给定一个\(n\times m\)的\(01\)矩阵,你可以选择一些行和一些列并将其中所有的\(01\)反转.求操作后最少剩下多少个\(1\). \(n\le ...

  2. CF662C Binary Table【FWT】

    CF662C Binary Table 题意: 给出一个\(n\times m\)的\(01\)矩阵,每次可以反转一行或者一列,问经过若干次反转之后,最少有多少个\(1\) \(n\le 20, m\ ...

  3. CF662C Binary Table FWT

    传送门 \(N \leq 20\)很小诶 一个暴力的思路是枚举行的翻转状态然后在列上贪心 复杂度为\(O(2^NM)\)显然过不去 考虑到可能有若干列的初始状态是一样的,那么在任意反转之后他们贪心的策 ...

  4. CF662C Binary Table (快速沃尔什变换FWT)

    题面 题解 我们会发现,如果单独的一列或一行,它的答案是O1确定的,如果确定了每一行是否变换,那么最后的答案也就简单了许多, 如果确定了行的变换状压下来是x(即x的i位表示第i行是否变换,理解就行), ...

  5. CF662C Binary Table 【状压 + FWT】

    题目链接 CF662C 题解 行比较少,容易想到将每一列的状态压缩 在行操作固定的情况下,容易发现每一列的操作就是翻转\(0\)和\(1\),要取最小方案,方案唯一 所以我们只需求出每一种操作的答案 ...

  6. CF662C Binary Table 枚举 FWT

    题面 洛谷题面 (虽然洛谷最近有点慢) 题解 观察到行列的数据范围相差悬殊,而且行的数量仅有20,完全可以支持枚举,因此我们考虑枚举哪些行会翻转. 对于第i列,我们将它代表的01串提取出来,表示为\( ...

  7. CF662C Binary Table (FWT板题)

    复习了一发FWT,发现还挺简单的... 没时间写了,就放一个博客吧:Great_Influence 的博客 注意这一句ans[i]=∑j⊗k=i​f[j]∗dp[k]ans[i]= ∑_{j⊗k=i} ...

  8. [CF662C] Binary Table(FWT)

    题意: https://www.cnblogs.com/cjyyb/p/9065801.html 题解:

  9. [CF662C]Binary Table

    luogu 题意 你有一个\(n*m\)的\(01\)矩阵.你可以把任意一行或者一列的\(01\)取反.求矩阵中最少的\(1\)的数量. \(n\le20,m\le10^5\) sol 很自然地有一个 ...

随机推荐

  1. LeetCode 681. Next Closest Time 最近时刻 / LintCode 862. 下一个最近的时间 (C++/Java)

    题目: 给定一个"HH:MM"格式的时间,重复使用这些数字,返回下一个最近的时间.每个数字可以被重复使用任意次. 保证输入的时间都是有效的.例如,"01:34" ...

  2. pytorch之 batch_train

    import torch import torch.utils.data as Data torch.manual_seed(1) # reproducible BATCH_SIZE = 5 # BA ...

  3. 学习Sparql

    一 . gstore--一种开源图数据库系统 https://www.docin.com/p-1951514687.html 二 . 使用 SPARQL 查询 RDF 数据 https://www.i ...

  4. shell使用变量的值,获取一个新的变量名的值

    [root@localhost ~]# cat s2.sh #!/bin/bash color_name="red" red=31 color=`eval echo '$'&quo ...

  5. C#基础知识学习(2)string类中的方法

    1.Compare 比较字符串 用来比较2个字符串的长度大小和值是否相同,相同则返回0,当x比y小返回-1,否则返回1,如果长度相同,且值不同,则返回1,代码如下 public static void ...

  6. 10个用于C#.NET开发的基本调试工具

    在调试软件时,工具非常重要.获取正确的工具,然后再调试时提起正确的信息.根据获取的正确的错误信息,可以找到问题的根源所在.找到问题根源所在,你就能够解决该错误了. 你将看到我认为最基本的解决在C# . ...

  7. Debian 10 安装无线网卡驱动 (rtl8822be)

    apt install firmware-realtek

  8. 与WinRT组件进行操作

    1,原理: WinRT是一个新的类库,应用程序可以用它访问操作系统的功能. 在内部,WinRT以组件的形式实现.COM Component Object Model- WinRT使用.net元数据来描 ...

  9. Ajax0002: 省市县三级联动案例

  10. Python——捕获异常

    一.什么是异常 """异常:错误,bug处理异常:尝试执行某句可能出现异常的语句, 若出错则用正确的代码去替代. try: 可能发生错误的代码except: 如果出现异常 ...