题解:AT_yahoo_procon2019_qual_e Odd Subrectangles
怎么题解全是线性基,来点高消做法。
Solution
性质:对矩阵进行初等变换(模 \(2\) 意义下),答案不变。
- 交换不用说。
- 一行加上另一行相当于异或两行。记 \(x,y\) 是原来两行的 \(1\) 个数,\(y'\) 是两行异或后的 \(1\) 个数,容易发现 \(y'\equiv x+y\pmod 2\),证明就是异或只会减少成对的 \(1\)。那么原来选了两行,就把第一行删掉;只选了第二行,就加入第一行。方案一一对应,答案不变。
- 一列加上另一列同理。
我们直接用高消消成对角线,记消完剩下 \(r\) 个 \(1\),答案就是:
\[2^{n+m-2r}\sum_{i=1}^{r}[i\bmod2=1]\binom{r}{i}3^{r-i}
\]
左边的 \(2^{n+m-2r}\) 是为 \(0\) 的行列,随便选;右边枚举选中的 \(1\) 的个数 \(i\),从 \(r\) 个中选出 \(1\) 个,剩下 \(r-i\) 个 \(1\) 只有不是行列同时选就行了,方案为 \(3^{r-i}\)。
用 bitset 优化,时间复杂度 \(\mathcal{O}(\dfrac{n^2m}{\omega})\)。
Code
namespace Milkcat {
using namespace Math;
typedef long long LL;
typedef pair<LL, LL> pii;
const int N = 305, mod = 998244353;
typedef Mint<mod> MI;
int n, m, x; MI ans;
bitset<N> A[N];
Combinations<MI> C;
int main() {
cin >> n >> m, C.init(n + m);
REP(i, 1, n) REP(j, 1, m)
cin >> x, A[i][j] = x;
int r = 0;
REP(k, 1, m) {
int t = 0;
REP(i, r + 1, n)
if (A[i][k]) t = i;
if (!t) continue;
r ++, swap(A[r], A[t]);
REP(i, 1, n)
if (i != r && A[i][k]) A[i] ^= A[r];
}
REP(i, 0, r)
if (i & 1) ans += C(r, i) * qpow((MI)3, r - i);
cout << ans * qpow((MI)2, n + m - r * 2) << '\n';
return 0;
}
}