Hiho1422 Harmonic Matrix Counter (高斯消元)

16年北京站A题 真的难啊..

题意:

定义和谐矩阵 就是每个元素和上下左右的xor值=0

输出一个超大数 然后最多800个询问 求字典序第k小的和谐矩阵 x y位置上的数

 

题解:

首先这个超大数的范围其实给了提示 $2^{800}$ 我们刚好想到枚举第一行 就有这么多种

确实 我们很容易发现 枚举了第一行之后 整个矩阵就可以算出来了

 

然后现在就要引出一个子题 P3164 

关于这个子题 在2020年5月份之前洛谷上的题解都不是太正的做法

正确做法是 把第一行的每个元素当作一个未知数 然后可以推到第n行

用第n行是和谐矩阵元素的关系得到m个方程式 高斯消元解之

 

我们再回到这个题 我们同样可以用这样的方法 高斯消元解之 然后我们开始写了!

先用高斯消元解出系数 然后把10进制的大数转化为二进制 为什么这题有第k小呢 因为我们解出了自由元啊!

如果自由元所能提供的解 小于k就直接无解了

然后我们惊奇的发现 字典序第k小的二进制刚好就是这个问题自由元的解 一一对应填进去就行了

然后这样交上去会得到 WA!!

为什么呢? 因为我们正常解出的自由元 所对应的未知数 实际上是可以提前更换位置的啊!

那么我们可以把自由元放在最前面 以得到字典序最小

#include <stdio.h>
#include <bits/stdc++.h>
#include <iostream>
#include <algorithm>
#include <bitset>
using namespace std;
const int MAXN = 805;

int n, m, q, x, y, len, rk, blen;
bitset<MAXN> a[MAXN][MAXN];
bitset<MAXN> b[MAXN];
int ans[MAXN];
int fr[MAXN];
char s[MAXN];
int t[MAXN], bit[MAXN << 3];

int dx[] = {-1, -1, -1, -2};
int dy[] = {-1, 0, 1, 0};

bool check(int x, int y) {
    if(x >= 1 && x <= n && y >= 1 && y <= m) return true;
    return false;
}

void gauss() {
    rk = 0;
    for(int i = 1, now = m; i <= m && now; now--) {
        for(int j = i; j <= m; j++) {
            if(b[j][now]) {
                std::swap(b[j], b[i]);
                break;
            }
        }
        if(!b[i][now]) {
            //fr[now] = 1;
            continue;
        }
        for(int j = i + 1; j <= m; j++) {
            if(b[j][now]) {
                b[j] ^= b[i];
            }
        }
        fr[now] = i;
        i++; rk++;
    }
}

void decode() {
    blen = 0;
    int llen = strlen(s + 1); memset(bit, 0, sizeof(bit));
    for(int i = 1; i <= llen; i++) t[i] = s[llen - i + 1] - '0';
    t[1]--; 
    int now = 1; while(t[now] < 0) t[now] += 10, now++, t[now]--;
    while(llen && !t[llen]) llen--;

    while(llen) {
        if(t[1] & 1) bit[++blen] = 1;
        else bit[++blen] = 0;

        int res = 0;
        for(int i = llen; i >= 1; i--) {
            int tmp = (t[i] + res * 10) / 2;
            res = (t[i] + res * 10) % 2;
            t[i] = tmp;
        }
        while(llen && !t[llen]) llen--;
    }
}

void get() {
    blen = max(blen, m - rk);
    memset(ans, 0, sizeof(ans));
    for(int i = 1; i <= m; i++) if(!fr[i]) ans[i] = bit[blen--];
    for(int i = 1; i <= m; i++) {
        if(fr[i])
        for(int j = i - 1; j; j--) {
            if(b[fr[i]][j]) ans[i] ^= ans[j];
        }
    }
}


int main() {
    while(~scanf("%d%d%d", &n, &m, &q)) {
        memset(fr, 0, sizeof(fr));
        for(int i = 1; i <= m; i++) b[i].reset();
        for(int i = 1; i <= n; i++)
            for(int j = 1; j <= m; j++)
                a[i][j].reset();
        for(int i = 1; i <= m; i++) a[1][i][i] = 1;

        for(int i = 2; i <= n; i++) {
            for(int j = 1; j <= m; j++) {
                for(int k = 0; k < 4; k++) {
                    int nx = i + dx[k];
                    int ny = j + dy[k];
                    if(check(nx, ny)) a[i][j] ^= a[nx][ny];
                }
            }
        }
        for(int i = 1; i <= m; i++) b[i] = a[n][i];
        for(int i = 1; i <= m; i++) {
            if(n - 1 >= 1) b[i] ^= a[n - 1][i];
            if(i - 1 >= 1) b[i] ^= a[n][i - 1];
            if(i + 1 <= m) b[i] ^= a[n][i + 1];
        }
        gauss();
        //for(int i = 1; i <= m; i++) cout << fr[i] << " "; puts("");

        //cout << m - rk << " ??" << endl;
        for(int cas = 1; cas <= q; cas++) {
            scanf("%s%d%d", s + 1, &x, &y);
            decode();
            //cout << "blen =" << blen <<endl;
            if(m - rk < blen) printf("?");
            else {
                get();
                /*
                for(int i = 1; i <= n; i++) {
                    for(int j = 1; j <= m; j++) {
                        int res = 0;
                        for(int k = 1; k <= m; k++)
                            if(a[i][j][k]) res ^= ans[k];
                        printf("%d ", res);
                    }
                    puts("");
                }*/
                
                int res = 0;
                for(int i = 1; i <= m; i++) if(a[x][y][i]) res ^= ans[i];
                printf("%d", res);
            }
        }
        puts("");
    }
    return 0;
}
/*
3 5 10
0 0 0 2 1
1 1 1
0 0 0 0 0
0 0 0 0 0
0 0 0 0 0
2 1 1
0 0 1 1 1
0 1 0 1 0
1 1 1 0 0
3 1 1
0 1 0 0 0
1 1 1 0 0
0 0 0 1 0
4 1 1
0 1 1 0 1
1 0 0 0 1
1 0 1 1 0
5 1 1
1 0 0 0 0
1 1 0 0 0
1 0 1 0 0
6 1 1
1 0 1 1 0
1 0 0 0 1
0 1 1 0 1
7 1 1
1 1 0 0 0
0 0 1 0 0
1 0 1 1 0
8 1 1
1 1 1 0 0
0 1 0 1 0
0 0 1 1 1
*/
View Code

 

posted @ 2020-04-29 21:48  lwqq3  阅读(236)  评论(0编辑  收藏  举报