[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 很自然地有一个 ...
随机推荐
- Luinx安装RocketMQ
一.RocketMQ环境 准备两台虚拟机,分别为master01 和master02 二.安装JDK(两台虚拟机相同步骤) 1. 检查当前虚拟机环境有没有JDK rpm -qa|grep java ( ...
- 安装MinGW出现 mingw-get: *** ERROR *** Get package:
个人的解决方法: 1.手机开个热点让电脑连上. 2.在Setting里面讲proxy关闭.
- 大数据篇:Zookeeper
Zookeeper 1 Zookeeper概念 Zookeeper是什么 是一个基于观察者设计模式的分布式服务管理框架,它负责和管理需要关心的数据,然后接受观察者的注册,一旦这些数据的状态发生变化,Z ...
- python学习(6)选择排序算法简单代码
选择排序的基本思想是:每一趟在n-i+1(i=1,2,…n-1)个记录中选取关键字最小的记录作为有序序列中第i个记录.基于此思想的算法主要有简单选择排序.树型选择排序和堆排序.[1] 简单选择排序的基 ...
- NR / 5G - Polar Coding
5G New Radio Polar Coding Introduction The selection of polar codes as the channel coding technique ...
- Andriod you must restart adb and eclipse
今天看着视频 学习着 andriod ,启动 的时候 竟然报错 我试了N种google来的方法,都失效,现在把我的解决方法告诉大家,希望能帮到大家. 首先,我先罗列下我搜到的方法,大家也可以尝试. 1 ...
- 以stm32f407为例,学习cortex-m4通用寄存器的用法
测试代码如下: int add(int a, int b, int c, int d, int e, int f) { return a+b+c+d+e+f; } int main(void) { i ...
- lwip nd没有实现ra,contik有参考
lwip中关于nd的实现,没有路由器的功能,不能发送ra 在contiki中发现有nd发送ra的实现, contiki/core/net/ipv6/uip-ds6.c 在rs的接收处理中,发送soll ...
- php/phpmyadmin新手式环境搭建
之前就在折腾 zabbix 的时候遇到一个情况, 安装 php6 的时候各种库丢失, 最重要的 gd 经常跑路 只是无意中遇到了一种小方式, 现在已经迷糊了, 前天因为在部署 phpAdmin 的时候 ...
- web渗透之XSS基本介绍
想学XSS必须得有基本得JS知识 JS基础BOM XSS漏洞原理 XSS(Cross Site Script),全称跨站脚本攻击.它指的是攻击者往web页面或者url里插入恶意JavaScript脚本 ...