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)$可以加过来,但要挑去其中$p$已经算过一次的情况,有$f(i-2,j)$这么多种,又要从$f(i-2,j)$中挑去那些$p$这一位算过一次的情况,$f(i-3,j \ \ xor \ \ 2^p)$,如此循环。但这样枚举完每个位置之后,每种好的情况其实算了$i$次,所以$i \times f(i,j)=\sum_{p=0}^{n-1} \sum_{t=1}^{i}(-1)^{t-1}f(i-t,j \ \ xor \ \ (2^p \times (t \mod 2)))$。

这样是$2^nn^3$的,但可以发现$\sum_{p=0}^{n-1}\sum_{t=3}^{i}(-1)^{t-1}f(i-t,j \ \ xor \ \ (2^p \times (t \mod 2)))=(i-2) \times f(i-2,j)$,所以整理一下,$i \times f(i,j)=\sum_{p=0}^{n-1}f(i-1,j \ \ xor \ \ 2^p)+(i-2-n)f(i-2,j)$。少一个$n$。

要再少一个得用FWT。不会。

 1 //#include<iostream>
 2 #include<cstring>
 3 #include<cstdio>
 4 //#include<math.h>
 5 //#include<set>
 6 //#include<queue>
 7 //#include<bitset>
 8 //#include<vector>
 9 #include<algorithm>
10 #include<stdlib.h>
11 using namespace std;
12
13 #define LL long long
14 int qread()
15 {
16     char c; int s=0,f=1; while ((c=getchar())<‘0‘ || c>‘9‘) (c==‘-‘) && (f=-1);
17     do s=s*10+c-‘0‘; while ((c=getchar())>=‘0‘ && c<=‘9‘); return s*f;
18 }
19
20 //Pay attention to ‘-‘ , LL and double of qread!!!!
21
22 int K,n;
23 #define maxn 1100011
24 int b[maxn],f[22][maxn];
25
26 int main()
27 {
28     K=qread(); n=qread();
29     {
30         char c;
31         for (int i=0;i<K;i++)
32             for (int j=1;j<=n;j++)
33             {
34                 while ((c=getchar())!=‘0‘ && c!=‘1‘);
35                 b[j]|=(c-‘0‘)<<i;
36             }
37         for (int i=1;i<=n;i++) f[0][b[i]]++;
38     }
39     int T=1<<K,ans=0x3f3f3f3f;
40     for (int i=1;i<=K;i++)
41     {
42         for (int j=0;j<T;j++)
43         {
44             if (i>1) f[i][j]=(i-2-K)*f[i-2][j];
45             for (int k=0;k<K;k++) f[i][j]+=f[i-1][j^(1<<k)];
46             f[i][j]/=i;
47         }
48     }
49     for (int i=0;i<T;i++)
50     {
51         int tmp=0;
52         for (int j=0;j<=K;j++) tmp+=min(j,K-j)*f[j][i];
53         ans=min(ans,tmp);
54     }
55     printf("%d\n",ans);
56     return 0;
57 }

原文地址:https://www.cnblogs.com/Blue233333/p/9206929.html

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

Codeforces663E. 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

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

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

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\),对答案的贡献

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

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}=\