Solution - Atcoder YPC2019E Odd Subrectangles

rizynvu發表於2024-07-29

首先對於 \(0 / 1\) 和為奇數,轉化為異或為 \(1\) 來考慮。

考慮如果已經確定了行的選取,又該如何計數。
考慮對於每一列,都處理好在對應行的位置的異或值。
然後記 \(\operatorname{c}_0, \operatorname{c}_1\) 表示列異或值為 \(0 / 1\) 的數量。

知道了 \(\operatorname{c}_0, \operatorname{c}_1\) 之後,就可以直接根據 \(\operatorname{c}_0, \operatorname{c}_1\) 來計數了。
首先對於 \(0\) 來說隨便選都行,方案數就為 \(2^{\operatorname{c}_0}\)
對於 \(1\) 來說就要求選的數量為奇數個,因為當 \(n\ge 1\) 時,\(\sum\limits_{i = 0}^n (-1)^i\binom{n}{i} = 0\),說明當 \(n\ge 1\)\(\sum\limits_{0\le i\le n, i \bmod 2 = 1} \binom{n}{i} = 2^{n - 1}\),於是可以知道這部分的數量為 \(\begin{cases}2^{\operatorname{c_1} - 1} & \operatorname{c_1}\ge 1\\ 0 & \operatorname{c_1} = 0\end{cases}\)
兩部分相乘,就知道最後的方案數為 \(\begin{cases}2^{m - 1} & \operatorname{c_1}\ge 1 \\ 0 & \operatorname{c}_1 = 0\end{cases}\)

那麼就可以去容斥,計數選擇行的方案數使得每一列對應異或出來都為 \(0\)\(\operatorname{c}_1 = 0\))。

這部分是好算的。
考慮異或線性基,方案數就為 \(2^{z}\)\(z\) 為自由元個數)。
證明考慮每個自由元都對應著一種不相同的線性組合方式,不管怎樣組合得到的方案都不一樣。

可以用 bitset 最佳化線性基。

時間複雜度 \(\mathcal{O}(\frac{nm^2}{\omega})\)

#include<bits/stdc++.h>
using ll = long long;
constexpr ll mod = 998244353;
inline ll qpow(ll b, ll a = 2, ll v = 1) {
   while (b) b & 1 && ((v *= a) %= mod), b >>= 1, (a *= a) %= mod;
   return v;
}
const int maxn = 3e2 + 10;
std::bitset<maxn> a, w[maxn];
int main() {
   int n, m; scanf("%d%d", &n, &m);
   ll tot = 1;
   for (int T = 1; T <= n; T++) {
      for (int i = 1, x; i <= m; i++)
         scanf("%d", &x), a.set(i, x);
      int f = 1;
      for (int i = 1; i <= m; i++) {
         if (! a[i]) continue;
         if (! w[i][i]) {
            f = 0, w[i] = a;
            break;
         }
         a ^= w[i];
      }
      if (f)
         (tot <<= 1) %= mod;
   }
   printf("%lld\n", (qpow(n) - tot + mod) * qpow(m - 1) % mod);
   return 0;
}

相關文章