Codeforces Round #553 (Div. 2) B. Dima and a Bad XOR

题目链接: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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值