CF662C Binary Table

LINK:CF662C Binary Table

一个nm的表格 每个元素都是0/1 每次操作可以选择一行或一列 将0/1翻转.可以操作无限次。

问最终局面最少有多少个1.\(n\leq 20,m\leq 100000\)

可以发现 先翻列再翻行等价于先翻行再翻列 先翻行再翻列再翻行 如果行是相同的 等价于翻列 反之同上一种情况。

对于任意一对行列之间的关系只有上述的几种情况 故可以发现 最优操作可以转换成 先翻行再翻列。

之所以这样是发现了行数较少 暴力枚举行的状态。

此时只有列能翻了 每一列都是独立的 所以此时找到每一列最多的某个数字即可。

复杂度 \(2^n\cdot n\cdot m\)通过不了。

可以发现 预处理一下每一列的状态 然后和枚举的状态异或一下就能得到新一列的状态 直接预处理某个状态下的1的个数即可。

那么就变成了\(2^n\cdot m\)

发现每一列的状态有可能会重复。

设 a[i]表示 列的状态为i出现的次数 b[i]表示0/1的最小值。

可以发现当状态为 w时此时全局的答案为 \(\sum_{i=0}^{2^n-1}a[i]\cdot b[i,xor,w]\)

复杂度好像更高了 = =.

不过没关系 我们想要求出来对于所有w的答案.设f[w]为行翻转情况为w时的答案。

有 \(f[w]=\sum_{i=0}^{2^n-1}a[i]\cdot b[i,xor,w]\)

变换一下形式\(f[w]=\sum_{ixorj=w}a[i]\cdot b[j]\)

惊喜的发现这竟然是一个异或卷积。预处理b数组和a数组之后FWT即可。真的妙。

const int MAXN=100010;
int n,m,maxx;
ll a[1<<21],b[1<<21],w[1<<21];
char c[21][MAXN];
inline void FWT_xor(ll *a,int op)
{
	for(int len=1;len<=maxx+1;len=len<<1)
	{
		int mid=len>>1;
		for(int j=0;j<=maxx;j+=len)
			for(int i=0;i<mid;++i)
			{
				ll x=a[i+j],y=a[i+j+mid];
				if(op==1)
				{
					a[i+j]=x+y;
					a[i+j+mid]=x-y;
				}
				else
				{
					a[i+j]=(x+y)>>1;
					a[i+j+mid]=(x-y)>>1;
				}
			}
	}
}
int main()
{
	freopen("1.in","r",stdin);
	gt(n);gt(m);
	rep(1,n,i)gc(c[i]);
	rep(1,m,j)
	{
		int s=0;
		rep(1,n,i)if(c[i][j]==‘1‘)s=s|(1<<(i-1));
		++a[s];
	}
	maxx=(1<<n)-1;
	rep(1,maxx,i)w[i]=w[i>>1]+(i&1);
	rep(0,maxx,i)b[i]=min(w[i],n-w[i]);
	FWT_xor(a,1);FWT_xor(b,1);
	rep(0,maxx,i)a[i]=a[i]*b[i];
	FWT_xor(a,-1);ll ans=INF;
	rep(0,maxx,i)ans=min(ans,a[i]);
	putl(ans);return 0;
}

注意xor 的FWT为 a0=a0+a1 a1=a0-a1

IFWT为 a0=(a0+a1)>>1;a1=(a0-a1)>>1;

原文地址:https://www.cnblogs.com/chdy/p/12616266.html

时间: 2024-10-09 16:04:42

CF662C Binary Table的相关文章

【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

【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\)的列

「CF662C」 Binary Table

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

【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)\}\) 我

[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 首先发

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)$可以加过来,但要挑去其中$

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\)表示对于某一列而言,若它经过各种行操作

CF 633 E. Binary Table

题目链接 题目大意:给定一个棋盘,棋盘上有0或1,你可以将一整行取反或者一整列取反,要使得最后剩的1最少.\((1\le n\le 20,1\le m\le 100000)\). 一个容易想到的思路就是先枚举行是否取反,然后列就看1的个数是否大于\(\frac{n}{2}\)考虑是否取反. 我们设函数\(f(x)\)表示\(min(x_0,x_1)\),\(x\)在二进制状态下0或1最少的个数. 我们设行的取反状态为\(k\),每列的最终状态就是\(sta[i]\ xor\ k\),对答案的贡献

Binary Table CodeForces - 662C (FWT)

大意: 给定$nm$大小的$01$矩阵, $1\le n\le 20,1\le m\le 1e5$, 可以任选行列翻转, 求最终$1$总数最少为多少. 显然有$O(m2^n)$的暴力算法 也就是枚举翻转哪些行, 然后对于一列, 若$1$的个数多于$0$的个数就翻转. 可以发现对于相同的列, 翻转行对它的影响是相同的. 用$a_i$记录状态为$i$的列的个数, $b_i$记录状态为$i$的列的贡献. 假设翻转行状态为$S$时答案为$f_{S}$, 枚举每种状态的列的贡献, 就有 $$f_{S}=\