题意:给定一个只含01的矩阵,可以把某一行或者某列反转反转,问经过一系列操作最终矩阵最少能剩下几个1
题解:由于n小于20,自然就想到状态压缩,枚举最终状态的第一列,然后贪心处理其他列,不过由于m太大,所以此法不可行,然后,就没有然后了
贴一波官方题解:
First let's examine a slow solution that works in O(2n · m). Since each row can be either inverted or not, the set of options of how we can invert the rows may be encoded in a bitmask of length n, an integer from 0 to (2n - 1), where the i-th bit is equal to 1 if and only if we invert the i-th row. Each column also represents a bitmask of length n (the bits correspond to the values of that row in each of the nrows). Let the bitmask of the i-th column be coli, and the bitmask of the inverted rows be mask. After inverting the rows the i-th column will become . Suppose that
contains
ones. Then we can obtain either k or (n - k) ones in this column, depending on whether we invert the i-th column itself. It follows that for a fixed bitmask mask the minimum possible number of ones that can be obtained is equal to
.
Now we want to calculate this sum faster than O(m). Note that we are not interested in the value of the mask itself, but only in the number of ones it contains (from 0 to n). Therefore we may group the columns by the value of
. Let dp[k][mask] be the number of such i that
, then for a fixed bitmask mask we can calculate the sum in O(n) —
.
What remains is to calculate the value of dp[k][mask] in a quick way. As the name suggests, we can use dynamic programming for this purpose. The value of dp[0][mask] can be found in O(m) for all bitmasks mask: each column coli increases dp[0][coli] by 1. Fork > 0, coli and mask differ in exactly k bits. Suppose mask and coli differ in position p. Then coli and differ in exactly(k - 1) bits. The number of such columns is equal to
, except we counted in also the number of columns colithat differ with
in bit p (thus, mask and coli have the same value in bit p). Thus we need to subtract dp[k - 2][mask], but again, except the columns among these that differ with mask in bit p. Let
; by expanding this inclusion-exclusion type argument, we get that the number of masks we are interested in can be expressed asdp[k - 1][next] - dp[k - 2][mask] + dp[k - 3][next] - dp[k - 4][mask] + dp[k - 5][next] - .... By summing all these expressions for each bit p from 0 to n, we get dp[k][mask] · k, since each column is counted in k times (for each of the bits p where the column differs frommask).
Therefore, we are now able to count the values of dp[k][mask] in time O(2n · n3) using the following recurrence:
This is still a tad slow, but we can speed it up to O(2n · n2), for example, in a following fashion:
#include <set>
#include <map>
#include <stack>
#include <queue>
#include <deque>
#include <cmath>
#include <vector>
#include <string>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
#define L(i) i<<1
#define R(i) i<<1|1
#define INF 0x3f3f3f3f
#define pi acos(-1.0)
#define eps 1e-12
#define maxn 1000100
#define MOD 1000000007
char s[100000];
int col[100000], dp[21][1 << 20];
int main()
{
int n, m;
scanf("%d %d", &n, &m);
for (int i = 0; i < n; i++)
{
scanf(" %s", s);
for (int j = 0; j < m; j++)
col[j] |= (s[j] - '0') << i;
}
for (int i = 0; i < m; i++)
dp[0][col[i]]++;
for (int k = 1; k <= n; k++)
for (int mask = 0; mask < (1 << n); mask++)
{
int sum = k > 1 ? (k - 2 - n) * dp[k - 2][mask] : 0;
for (int p = 0; p < n; p++)
sum += dp[k - 1][mask ^ (1 << p)];
dp[k][mask] = sum / k;
}
int ans = n * m;
for (int mask = 0; mask < (1 << n); mask++)
{
int cnt = 0;
for (int k = 0; k <= n; k++)
cnt += min(k, n - k) * dp[k][mask];
ans = min(ans, cnt);
}
printf("%d\n", ans);
return 0;
}