【luogu CF226D】The table(找性质)(模拟)
The table
题目链接:luogu CF226D
题目大意
给你一个二维矩阵,然后你可以选择一些列和行把它们反转,使得每一行和每一列的数的和都是非负数。
输出任意一个合法解。
思路
首先看到值域只有 \(-100\sim100\) 考虑从这里入手。
你考虑如果你直接暴力找会怎么样。
每次就会找到一个小于 \(0\) 的行或者列。
然后取反,所有数的和就至少会 \(+2\)。
然后你发现你这么暴力搞下去最小是 \(-10000\),最大是 \(10000\),那你最多加 \((10000-(-10000))/2=10000\) 次。
然后你发现这就可以过了。
(记得如果多次翻转就相当于不操作)
代码
#include<cstdio>
#include<vector>
using namespace std;
int n, m, a[101][101];
bool lop[101], rop[101];
pair <int, int> 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 <int, int> 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;
}