Yahoo Programming Contest 2019 E

E - Odd Subrectangles

链接

题意:

  n*m的01矩阵,选出一些行和一些列,计算多少个选的方式,使得相交的点的权值和,是奇数,n,m<=300。

分析:

  考虑选出了行,有多少列满足。

  把每一行的01序列看成一个二进制数,如果选出的行的异或起来是0,那么说明不论怎么选列的集合,都不能是奇数。如果异或起来不是0,那么选列的方案数是$2^{m-1}$。

  于是考虑多少种行的选法,使得异或起来不是0,线性基求出基的大小,设为cnt,那么$2^{n-cnt}$就是异或和为0的方案数,用总的减去,就是异或和不是0的方案数。

代码:

数组模拟:8ms

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<iostream>
#include<cmath>
#include<cctype>
#include<set>
#include<queue>
#include<vector>
#include<map>
using namespace std;
typedef long long LL;

inline int read() {
    int x=0,f=1;char ch=getchar();for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1;
    for(;isdigit(ch);ch=getchar())x=x*10+ch-'0';return x*f;
}

const int N = 305, mod = 998244353;
int a[N][N], b[N][N];

int ksm(int a,int b) {
    int res = 1;
    while (b) {
        if (b & 1) res = 1ll * res * a % mod;
        a = 1ll * a * a % mod;
        b >>= 1;
    }
    return res;
}

int main() {
    int n = read(), m = read(), cnt = 0;
    for (int i = 1; i <= n; ++i) 
        for (int j = 1; j <= m; ++j) a[i][j] = read();
    for (int i = 1; i <= n; ++i) 
        for (int j = 1; j <= m; ++j) 
            if (a[i][j]) {
                if (!b[j][j]) {
                    for (int k = j; k <= m; ++k) b[j][k] = a[i][k];
                    cnt ++;
                    break;
                }
                else {
                    for (int k = j; k <= m; ++k) a[i][k] ^= b[j][k];
                }
            }
    cout << 1ll * (ksm(2, n) - ksm(2, n - cnt) + mod) % mod * ksm(2, m - 1) % mod;
    return 0;
}
View Code

bitset优化:4ms

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<iostream>
#include<cmath>
#include<cctype>
#include<set>
#include<queue>
#include<vector>
#include<map>
#include<bitset>
using namespace std;
typedef long long LL;

inline int read() {
    int x=0,f=1;char ch=getchar();for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1;
    for(;isdigit(ch);ch=getchar())x=x*10+ch-'0';return x*f;
}

const int N = 305, mod = 998244353;
bitset<N>a[N], b[N];

int ksm(int a,int b) {
    int res = 1;
    while (b) {
        if (b & 1) res = 1ll * res * a % mod;
        a = 1ll * a * a % mod;
        b >>= 1;
    }
    return res;
}

int main() {
    int n = read(), m = read(), cnt = 0;
    for (int i = 1; i <= n; ++i) 
        for (int j = 1; j <= m; ++j) a[i][j] = read();
    for (int i = 1; i <= n; ++i) 
        for (int j = 1; j <= m; ++j) 
            if (a[i][j]) {
                if (!b[j][j]) { 
                    b[j] = a[i];
                    cnt ++;
                    break;
                }
                else {
                    a[i] ^= b[j];
                }
            }
    cout << 1ll * (ksm(2, n) - ksm(2, n - cnt) + mod) % mod * ksm(2, m - 1) % mod;
    return 0;
}
View Code
原文地址:https://www.cnblogs.com/mjtcn/p/10375337.html