Yahoo Programming Contest 2019 E - Odd Subrectangles
E - Odd Subrectangles
题意:
n*m的01矩阵,选出一些行和一些列,计算多少个选的方式,使得相交的点的权值和,是奇数,n,m<=300。
分析:
考虑选出了行,有多少列满足。
把每一行的01序列看成一个二进制数,如果选出的行的异或起来是0,那么说明不论怎么选列的集合,都不能是奇数。如果异或起来不是0,那么选列的方案数是$2^{m-1}$。
于是考虑多少种行的选法,使得异或起来不是0,线性基求出基的大小,设为cnt,那么$2^{n-cnt}$就是异或和为0的方案数,用总的减去,就是异或和不是0的方案数。
代码:
数组模拟:8ms
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#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; }
bitset优化:4ms
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#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; }