2019校招真题在线编程 古巴比伦迷宫 (线性基)

题目描述

一群探险家被困古巴比伦迷宫 ,经过努力,探险家破译出了密码。原来通关需要先打开前方的M个机关的任意一个或多个为打开状态,然后关闭所有机关才能安全通过。探险家还发现了一种带有凸起的圆盘,圆盘可以用来同时反转若干个机关的状态(打开状态反转为关闭状态,关闭状态反转为打开状态,这若干个机关必须同时反转)。为了速记,探险家们用十六进制数字表示一个圆盘。如圆盘能同时控制第3、4、5个开关,圆盘就记为1C(11100)。每次操作一个圆盘,比特位为1的位置的机关同时被反转;而且每个圆盘使用一次后就会碎掉。目前探险家收集到了N个圆盘,问现在探险家可以顺利走出迷宫么?

若探险家手里有0、1、2、3、5五个圆盘,M=7,由于存在1 xor 2 xor 3 = 0, 因此结果是yes;
若探险家手里有0、1、2、2、5五个圆盘,M=7,由于存在2 xor 2 = 0, 因此结果是yes;
若探险家手里有0、1、3、5、9五个圆盘,M=7,由于不存组合使得 xor = 0, 因此结果是no。

 

输入描述:

包含多组数据,第一行是数据组数。

每组数据中首行为M N,M为机关个数,M <= 360(大部分情况下小于40),N为圆盘个数,
N<=50000;其余为N行圆盘的16进制ID,可以保证每行输入小于2^M

输出描述:

每组一行输出,满足条件输出yes,反之输出no

示例1

输入

复制

2
2 3
0
2
2
5 2
4
1C

输出

复制

yes
no

题解:线性基的模板题

线性基请参考:线性基

#include <bits/stdc++.h>
using namespace std;
const int N = 400;
bitset<N> b1[N], b2[N];
char str[N];
string buff;
int main() {
    for (int i = 1; i < N; i++) b1[i].set(i - 1);
    vector <string> ss;
    function<void(int, string)> dfs = [&](int i, string s){if(i == 4) {ss.push_back(s); return;} else {dfs(i + 1, s + '0'); dfs(i + 1, s + '1');}};
    dfs(0, "");
    sort(ss.begin(), ss.end());
    ios::sync_with_stdio(false);
    cin.tie(0);
    int tt, m, n;
    scanf("%d", &tt);
    while(tt--){
        for (int i = 0; i < N; i++) b2[i] = 0;
        scanf("%d %d", &m, &n);
        bool flag = false;
        bitset<N> bt = 0;
        for (int i = 0; i < m; i++) bt.set(i);
        for (int i = 0; i < n; i++){
            scanf("%s", str);
            buff = "";
            int len = strlen(str);
            if(flag) continue;
            if(len == 1 && str[0] == '0') continue;
            for (int j = 0; j < N / 4 - len; j++) buff.append("0000");
            for (int j = 0; j < len; j++) {
                if(str[j] >= '0' && str[j] <= '9') buff.append(ss[str[j] - '0']);
                else buff.append(ss[str[j] - 'A' + 10]);
            }
            bitset<N> t(buff);
            t &= bt;
            for (int j = 1; j < N; j++){
                if((t & b1[j]) != b1[0]){
                    if(b2[j] == b1[0]){
                        b2[j] = t;
                        break;
                    } else {
                        t ^= b2[j];
                        if(t == b1[0]){
                            flag = true;
                            break;
                        }
                    }
                }
            }
        }
        puts(flag ? "yes" : "no");
    }
    return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值