Cordforces 1774D题解
题目链接: https://codeforces.com/problemset/problem/1774/D
Description:
给定n个长为m的二进制串,每次可以选出任意两个,然后交换这两个二进制串同一列的数。求最少的操作次数,使得每一行含有的1的数量相等。
input:
第一行是测试案例的数目。
每个测试案例的第一行包含两个字符n, m(2 ≤ n ≤ 10^5, 2 ≤ m ≤ 10^5)。
接下来n行每行包含m个仅为0或1的数字,是二进制串的具体内容。
output:
如果没有办法做到每行含有的1数目相等,输出-1,否则在第一行输出最少的操作次数k,
然后接下来k行,每行输出三个字符,其中前两个是选中的行,第三个是选中的列
Sample input:
3
3 4
1 1 1 0
0 0 1 0
1 0 0 1
4 3
1 0 0
0 1 1
0 0 1
0 0 0
2 2
0 0
0 1
Sample output:
1
2 1 1
1
4 2 2
-1
先统计每行1的个数, 并且计算出来每行应该有多少个。然后按列遍历,对于第j列, 如果第i行1的个数多于平均值并且g[i][j]是1的话就记录下来,如果第i行1的个数小于平均值并且g[i][j]是0的话也记录下来。
Code:
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
#define int LL
struct Node {
int x, y, z;
};
void solve(void) {
int n, m; cin >> n >> m;
int cnt = 0; int f[n + 1];
memset(f, 0, sizeof f);
vector<int> g[n + 1];
for(int i = 1; i <= n; i ++) {
g[i].resize(m + 1);
for(int j = 1; j <= m; j ++) {
cin >> g[i][j];
if(g[i][j]) {
cnt ++;
f[i] ++;
}
}
}
if(cnt % n) {
cout << "-1\n";
return;
}
cnt /= n;
vector<Node> ans;
for(int i = 1; i <= m; i ++) {
queue<int> que1, que2;
for(int j = 1; j <= n; j ++) {
if(f[j] > cnt && g[j][i]) que1.push(j);
if(f[j] < cnt && !g[j][i]) que2.push(j);
}
while(que1.size() && que2.size()) {
int x = que1.front();
int y = que2.front();
que1.pop();
que2.pop();
f[x] --; f[y] ++;
ans.push_back({x, y, i});
}
}
cout << ans.size() << '\n';
for(int i = 0; i < ans.size(); i ++) {
cout << ans[i].x << ' ' << ans[i].y << ' ' << ans[i].z << '\n';
}
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0);
int t; cin >> t;
while(t --) solve();
}