【luogu CF226D】The table(找性质)(模拟)


The table

题目链接:luogu CF226D

题目大意

给你一个二维矩阵,然后你可以选择一些列和行把它们反转,使得每一行和每一列的数的和都是非负数。
输出任意一个合法解。

思路

首先看到值域只有 \(-100\sim100\) 考虑从这里入手。

你考虑如果你直接暴力找会怎么样。
每次就会找到一个小于 \(0\) 的行或者列。
然后取反,所有数的和就至少会 \(+2\)

然后你发现你这么暴力搞下去最小是 \(-10000\),最大是 \(10000\),那你最多加 \((10000-(-10000))/2=10000\) 次。
然后你发现这就可以过了。
(记得如果多次翻转就相当于不操作)

代码

#include
#include

using namespace std;

int n, m, a[101][101];
bool lop[101], rop[101];

pair  ck() {
	for (int i = 1; i <= n; i++) {
		int sum = 0;
		for (int j = 1; j <= m; j++)
			sum += a[i][j];
		if (sum < 0) {
			for (int j = 1; j <= m; j++)
				a[i][j] *= -1;
			return make_pair(0, i);
		}
	}
	for (int i = 1; i <= m; i++) {
		int sum = 0;
		for (int j = 1; j <= n; j++)
			sum += a[j][i];
		if (sum < 0) {
			for (int j = 1; j <= n; j++)
				a[j][i] *= -1;
			return make_pair(1, i);
		}
	}
	return make_pair(0, 0);
}

int main() {
	scanf("%d %d", &n, &m);
	for (int i = 1; i <= n; i++)
		for (int j = 1; j <= m; j++) {
			scanf("%d", &a[i][j]);
		}
	
	while (1) {
		pair  val = ck();
		if (val == make_pair(0, 0)) break;
		if (val.first) rop[val.second] ^= 1;
			else lop[val.second] ^= 1;
	}
	
	int num = 0;
	for (int i = 1; i <= n; i++)
		if (lop[i]) num++;
	printf("%d ", num); for (int i = 1; i <= n; i++) if (lop[i]) printf("%d ", i);
	putchar('\n');
	num = 0;
	for (int i = 1; i <= m; i++)
		if (rop[i]) num++;
	printf("%d ", num); for (int i = 1; i <= m; i++) if (rop[i]) printf("%d ", i);
	
	return 0; 
}