【CF662C】Binary Table 按位处理

【CF662C】Binary Table

题意:给你一个$n\times m$的01网格,你可以进行任意次操作,每次操作是将一行或一列的数都取反,问你最多可以得到多少个1?

$n\le 20,m\le 10^5$

题解:我也不知道叫啥了,说状压也不对,说fwt也不太对,就叫按位处理得了。

显然有$O(2^nm)$暴力,先枚举每行是否取反,然后枚举每列,如果0多就取反,否则不取。

但我们发现我们完全可以将本质相同的列一起处理,什么叫本质相同的列呢?假如我们对每行是否取反的状态为S,则所有$xor S$中1的个数相同的列我们都认为是相同的。那么现在问题就变成了对于所有S,$xor S$中1的个数为i的列的个数是多少。我们可以设f[S][i]表示这个状态,初始时f[T][0]++(T是某一列的状态)。然后我们枚举二进制的每一位是否取反,再从大到小枚举1的个数,进行转移即可。最后的答案就是$max\{\sum\limits_{i=0}^n f[S][i]\times max\{i,n-i\}\}$。

#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
int n,m,ans;
char s[21][100001];
int f[21][(1<<20)+1];
int main()
{
	scanf("%d%d",&n,&m),ans=1<<30;
	int i,j,k;
	for(i=0;i<n;i++)	scanf("%s",s[i]);
	for(i=0;i<m;i++)
	{
		int tmp=0;
		for(j=0;j<n;j++)	if(s[j][i]==‘1‘)	tmp|=1<<j;
		f[0][tmp]++;
	}
	for(i=0;i<n;i++)	for(j=n;j;j--)	for(k=0;k<(1<<n);k++)	f[j][k]+=f[j-1][k^(1<<i)];
	for(k=0;k<(1<<n);k++)
	{
		int tmp=0;
		for(i=0;i<=n;i++)	tmp+=min(i,n-i)*f[i][k];
		ans=min(ans,tmp);
	}
	printf("%d",ans);
	return 0;
}

原文地址:https://www.cnblogs.com/CQzhangyu/p/8594527.html

时间: 2024-11-06 03:31:12

【CF662C】Binary Table 按位处理的相关文章

CF662C Binary Table

LINK:CF662C Binary Table 一个nm的表格 每个元素都是0/1 每次操作可以选择一行或一列 将0/1翻转.可以操作无限次. 问最终局面最少有多少个1.\(n\leq 20,m\leq 100000\) 可以发现 先翻列再翻行等价于先翻行再翻列 先翻行再翻列再翻行 如果行是相同的 等价于翻列 反之同上一种情况. 对于任意一对行列之间的关系只有上述的几种情况 故可以发现 最优操作可以转换成 先翻行再翻列. 之所以这样是发现了行数较少 暴力枚举行的状态. 此时只有列能翻了 每一列

「CF662C」 Binary Table

「CF662C」 Binary Table 题目链接 题目所给的 \(n\) 很小,于是我们可以考虑这样一种朴素做法:暴力枚举第 \(i\) 行是否翻转,这样每一行的状态就确定了,这时取每一列 \(0/1\) 个数较小的数字即可(因为每一列也可以翻转).这样的时间复杂度是 \(O(m\cdot2^n)\). 但是显然这样过不了. 我们发现表格的具体行列对我们的答案是没有影响的.即我们只需要知道状态为 \(x\) 的行或者状态为 \(x\) 的列的个数即可.由于 \(n\le20\),这启发我们对

【CF662C】Binary Table(FWT)

[CF662C]Binary Table(FWT) 题面 洛谷 CF 翻译: 有一个\(n*m\)的表格(\(n<=20,m<=10^5\)), 每个表格里面有一个\(0/1\), 每次可以将一行或者一列的\(01\)全部翻转 回答表格中最少有多少个\(1\) 题解 发现\(n\)很小,\(m\)很大 状压是跑不掉了 如果我们确定翻转哪些行,那么答案唯一确定(贪心的选每一列中\(0/1\)的较小值) 相同的列显然可以合并, 把每一列按照\(01\)状压,记\(a[i]\)为状态为\(i\)的列

UVA11127- Triple-Free Binary Strings(DFS+位运算)

题目链接 题意:给出长度为n的字符串,字符串由'1','0','*'组成,其中'*'可以任意替换为'1','0',求不存在连续3个相同子串的字符串的最多个数. 思路:我们可以利用二进制的形式来表示字符串,进行DFS.利用位运算的左移来表示在'*'位置上放置'1',注意在递归的过程中注意判断之否存在3个连续相同的子串. 代码: #include <iostream> #include <cstdio> #include <cstring> #include <alg

【CF662C】Binary Table

题目 好吧,我连板子都不会了 有一个非常显然的做法就是\(O(2^nm)\)做法就是枚举每一行的状态,之后我们贪心去看看每一列是否需要翻转就好啦 显然这个做法非常垃圾过不去 首先我们发现每一列都不超过\(20\),考虑把每一列都压成一个状态 我们考虑设一些奇怪的东西 设\(g_i\)表示行的翻转状态为\(i\)的最优解,\(f_i\)表示有多少列的状态为\(i\),\(dp_i\)表示\(i\)这个状态最少有多少个\(1\) 显然\(dp_i=min\{bit(i),n-bit(i)\}\) 我

Codeforces663E. Binary Table

$n \leq 20,m \leq 100000$的01矩阵,可整行整列01翻转,问最少剩几个1. 一个暴力的做法是枚举$2^n$种行翻转然后$m$列扫一遍.但其实在行翻转情况确定的情况下我们只关心两个东西:某一列在行翻转后剩几个1,以及有几个这样的列.$f(i,j)$--在行翻转$j$的情况下,有$i$个1的有多少列.其实就是与$j$有$i$个位不同的有多少列.可以枚举每一个位置$p$,那么这一位上与$j$不同的状态$f(i-1,j \ \ xor \ \ 2^p)$可以加过来,但要挑去其中$

[CF792D] Paths in a Complete Binary Tree (规律, 位运算, lowbit)

题目链接:http://codeforces.com/problemset/problem/792/D 画出树,找找规律,画图就好了.不算麻烦. 往下走的时候特判是不是叶子,往上走的时候特判是不是根.其余时候按照规律转移就是. 感觉可以推广到建树上,可以缩小常数是极好的. 1 #include <bits/stdc++.h> 2 using namespace std; 3 4 typedef long long LL; 5 LL lowbit(LL x) { return x & (

[Codeforces]663E Binary Table

某变换好题.不过听说还有O(2^n*n^2)DP的…… Description 给定一个n*m的01矩阵,你可以选择对任意行和任意列取反,使得最终“1”的数量尽量少. Input 第一行两个整数n,m. 接下来n行,每行m个字符,描述一个01矩阵. Output 一个整数表示最少的1的数量. Sample Input 3 4 0110 1010 0111 Sample Output 2 HINT 1 <= n <= 20,1 <= m <= 100000. Solution 首先发

Codeforces 662C Binary Table(快速沃尔什变换)

Problem 给定一个n(≤20)*m(≤100 000)的01矩阵,每次操作可以将一行或一列取反. 求最终1的最少个数. Solution 前置技能:快速沃尔什变换(FWT). 观察到n较小,考虑\(O(2^n)\)枚举每一行选或不选. 不妨设f(x)表示行的操作状态为x时(我们可用一个二进制数表示状态),经过各种列操作后所得到的最少的1的个数. 可以\(O(m)\)再扫一遍所有列.但显然T飞了. 定义\(C_j\)表示有多少列的状态为j:\(E_k\)表示对于某一列而言,若它经过各种行操作