题目链接:https://codeforces.com/contest/1151/problem/B
题意:有一个 n × m n×m n×m的矩阵,你从每一行中选一个数出来,最后选出来的所有的数的异或和不能为0,问是否可以做到,可以输出每行选的那个数的列值,否则输出"NIE"
解题心得:
直接统计每一行所有二进制中每一位可以从多少列取到1,统计完后直接枚举每一个二进制位,将只能取1的行取完,只能取0的行取完,看这个二进制位是否是1,如果是1,剩下的行中只取当前二进制位是0的那个数。如果当前二进制位是0,找一行当前二进制位是1的取,然后全取0。
思路感觉好绕啊,比赛就打崩了,删了写写了删,最后自暴自弃。最后还是昏昏沉沉的写完了。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int, int> P;
const int maxn = 510;
int n ,m, cnt[maxn][15] ,ans[maxn], bit[maxn][maxn][15], matrix[maxn][maxn];
/*cnt记录每一行的每个二进制位取1可以从多少个列取到
* ans记录每一行取的数是哪一个
* bit[i][j]记录第i行j列这个数的每一个二进制位是多少
*/
void init() {
scanf("%d%d",&n, &m);
for(int i=1;i<=n;i++) {
for(int j=1;j<=m;j++) {
scanf("%d", &matrix[i][j]);
for(int k=0;k<=10;k++) {
if(matrix[i][j] & (1<<k)) {
cnt[i][k]++;
bit[i][j][k] = 1;
}
}
}
}
}
int if_find_ans(){
int c = -1;
for(int k=0;k<=10;k++) {//枚举每一个二进制位是否可以最后异或为1
int mo = 0;
for(int i=1;i<=n;i++) {
if(cnt[i][k] == m) {//一行的第k个二进制位只能取1
mo++;
} else if(cnt[i][k] == 0){//一行的第k个二进制位只能取0
continue;
}
}
for(int i=1;i<=n;i++) {
if(cnt[i][k] != m && cnt[i][k] != 0) {
if(mo%2 == 0) {//前面取完之后可以随意取,如果是0,取一个1跳出就行
mo++;
break;
}
}
}
if(mo%2 == 1) {//找到答案
c = k;
break;
}
}
if(c == -1) {
puts("NIE");
return -1;
}
return c;
}
void get_ans(int c) {
int mo = 0;
for(int i=1;i<=n;i++) {
if(cnt[i][c] == m) {
ans[i] = 1;
mo++;
} else if(cnt[i][c] == 0) {
ans[i] = 1;
}
}
for(int i=1;i<=n;i++) {
if(cnt[i][c] != m && cnt[i][c] != 0) {
if(mo%2 == 0) {
for(int j=1;j<=m;j++) {
if(bit[i][j][c] == 1) {
mo++;
ans[i] = j;
break;
}
}
} else {
for(int j=1;j<=m;j++) {
if(bit[i][j][c] == 0) {
ans[i] = j;
break;
}
}
}
}
}
puts("TAK");
for(int i=1;i<=n;i++) {
printf("%d ", ans[i]);
}
}
int main()
{
init();
int c = if_find_ans();//二进制中的第c位异或起来可以是1
if(c == -1) return 0;
else {
get_ans(c);
}
return 0;
}